有谁知道为什么 TWEAK 例程在 BUILD 例程之前被命中?

Tim*_*son 8 construction object tweak rakudo raku

最小代码:

 #!/usr/bin/raku

 class   Widget {
         submethod TWEAK(:$content, :$styles) {
                 say "t1\n";
         }
 }

 class   File is Widget {
         submethod BUILD() {
                 say "b1";
         }
 }

 my $xml = File.new();
Run Code Online (Sandbox Code Playgroud)

和输出:

 t1

 b1
Run Code Online (Sandbox Code Playgroud)

相关文档位于https://docs.raku.org/language/objects#Object_construction。我引用:“在调用 BUILD 方法之后,调用名为 TWEAK 的方法(如果存在),再次将所有命名参数传递给 new”。

我正在使用 Fedora 32 附带的 rakudo 版本(rakudo-0.2020.02-1.fc32.x86_64 所以可能是今年 2 月)。

Sci*_*mon 7

向每个缺少它们的示例类添加TWEAKandBUILD方法的快速实验显示调用顺序是Widget::BUILD-> Widget::TWEAK-> File::BUILD-> File::TWEAK

所以我认为问题在于文档的措辞“在调用 BUILD 方法之后,调用名为 TWEAK 的方法(如果存在),再次将所有命名参数传递给 new。”

我想,这应该有可能是“BUILD方法被调用后为每个类,命名为TWEAK方法被调用该类所有传递给新的命名参数,如果存在的话,一次。”

这将记录似乎正在发生的事情。

注意:自从回答这个问题以来,文档已经更新以反映代码的运行方式。

  • 完全是这样。所以这要么是糟糕的文档,要么是一个错误。我在文档上提出了 PR,假设它是第一个:https://github.com/Raku/doc/pull/3656 我将让您决定是否是第二个:) (2认同)

use*_*601 6

TWEAK之后被调用BUILD

然而,子类仍然需要遵循父类的构造例程。考虑以下代码:

class Foo {
  submethod TWEAK { say "Foo tweak" }
  submethod BUILD { say "Foo build" }
}

class Bar is Foo {
  submethod TWEAK { say "Bar tweak" }
  submethod BUILD { say "Bar build" }
}

Bar.new
Run Code Online (Sandbox Code Playgroud)

如果运行它,您可以很快看到发生了什么:

Foo build
Foo tweak
Bar build
Bar tweak
Run Code Online (Sandbox Code Playgroud)

基本上,每个类的构造函数方法在为父类调用之前不会被调用,这意味着在构建和调整时,您可以假设父类的属性已正确初始化。

这实际上就是这些方法需要成为子方法的原因,否则,如果父类的构建方法引用了私有属性,并且子类继承了父类方法,则会出现错误,因为专利和子类都会调用它,但孩子无权访问。

  • @TimothyNelson 虽然我可以理解为什么有人可能希望首先调用所有构建,但在进一步研究(https://github.com/Raku/doc/pull/3656#issuecomment-700133267)时,我发现我在为什么:每个类都需要能够在不受子类干扰的情况下初始化自身,否则可能会处于不一致的状态。 (2认同)