【问题标题】:Instantiate a Raku class, and update an instance variable in the constructor实例化一个 Raku 类,并在构造函数中更新一个实例变量
【发布时间】:2021-02-17 05:16:08
【问题描述】:

我似乎很难理解如何正确使用 Raku 中的类。

我正在尝试创建一个将在整个 cro 应用程序中使用的“数据库”类。但是我似乎不明白如何在对象构造(BUILD?)时设置实例变量。

下面的类显示了我在调用它时遇到的问题的示例:

调用:

my $db = Database.new(dsn => 'update me!');
say "what value is foo: " ~ $db.what-is-foo(); # prints "what value is foo: 0" but expecting 123

我的班级:

use DB::Pg;

class Database {
    has Str    $.dsn is required;
    has DB::Pg $!dbh = Nil;
    has Int    $!foo = 0;

    method new (:$dsn) {
        my $dbh = DB::Pg.new(conninfo => :$dsn);
        my $foo = 123;
        return self.bless(:$dsn, dbh => $dbh, foo => $foo);
    }

    method what-is-foo() {
        return $!foo;
    }
}

所以在我的类构造函数中,我想为数据库 dsn 传递一个命名参数。 在我计划连接的新方法中,并为连接句柄设置一个实例变量。

在这个例子中,我使用一个简单的整数 (foo) 作为测试。

到目前为止,我发现 the docs here 不包含此类模式的示例,除了 pehaps:

use DB::Pg;

class Database {
    has Str    $.dsn is required;
    has DB::Pg $!dbh = Nil;
    has Int    $!foo = 0;

    submethod BUILD(:$dsn) {
        $!dbh = DB::Pg.new(conninfo => :$dsn);
        $!foo = 123;
    }

    method what-is-foo() {
        return $!foo;
    }
}

但这给了我:

The attribute '$!dsn' is required, but you did not provide a value for it.

任何帮助将不胜感激!

【问题讨论】:

    标签: raku


    【解决方案1】:

    只有具有公共访问器的属性(即. twigil)会自动使用bless 设置。

    你有两种方法来处理这个问题。您可以将它们设置为TWEAKBUILD,或者您可以将属性is built 添加到属性中以自动为您完成此操作。在这种情况下属性is built 可能是最简单的,只需说has Int $!foo is built = 0。但值得扩展其他选项:

    如果您包含BUILD 方法,则您需要自行负责所有设置。这意味着公共 私有属性。但是您可以通过巧妙地命名参数来让您的生活更轻松:

    method BUILD (:$!dsn, :$!dbh, :$!foo) { }
    

    其实就是这样。签名将传入的值绑定到$!dsn 等,这当然会为整个对象实例设置它们。当然,你也可以在这里做更有趣的事情。无论如何,在BUILD 之后,还会进行一些额外的检查。 (1)如果不设置$!dsn,因为有is required,会报错。 (2) 如果您最终没有设置$!foo$!dbh,它们将获得它们的默认值。

    使用TWEAK,您将获得与使用BUILD 相同的参数,但所有初始设置都已完成(构建或自动绑定到公共属性和所有默认值,并保证所需的值在那里)。您只是有机会在最后一秒进行一些调整。

    【讨论】:

    • 这是一个很好的答案,解释了很多。谢谢!在这种情况下,我沿着建造路线走。但我有更好的理解,这让我相信我会在不久的将来的某个时候使用 TWEAK
    • 我认为有必要更新文档以使用 TWEAK 而不是 BUILD。这个想法是 10 次中有 9 次是你想要的。在其他时候,您可能想要 BUILD 然后您可能想要编写一个新方法。
    • 相反,如果您希望属性具有访问器但在对象创建时设置它,您可以说has $.foo is built(False)。遗憾的是,还没有没有语法糖允许has $.foo is !built
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多