为什么没有填充我的对象属性?

Why isn't my object attribute populated?

鉴于此过于简化的 XML 文件:

<Foo>Bar</Foo>

以及提取 Foo 元素值的代码:

use XML::Rabbit;
use Data::Dump::Tree;

class RunInfo does XML::Rabbit::Node {
    has $.foo is xpath("/Foo");
}

sub MAIN ( $file! ) {

    my $xml = RunInfo.new( file => $file );

    dump $xml;

    put "-----------------------";
    put "Foo is $xml.foo()";
}

您会看到 foo 的值为 Nil,即使输出显示 Foo is Bar:

.RunInfo @0
├ $.foo = Nil
├ $.context is rw = .XML::Document @1
│ ├ $.version = 1.0.Str
│ ├ $.encoding = Nil
│ ├ %.doctype = {0} @2
│ ├ $.root = .XML::Element @3
│ │ ├ $.name is rw = Foo.Str
│ │ ├ @.nodes is rw = [1] @4
│ │ │ └ 0 = .XML::Text @5
│ │ │   ├ $.text = Bar.Str
│ │ │   └ $.parent is rw = .XML::Element §3
│ │ ├ %.attribs is rw = {0} @7
│ │ ├ $.idattr is rw = id.Str
│ │ └ $.parent is rw = .XML::Document §1
│ ├ $.filename = example.xml.Str
│ └ $.parent is rw = Nil
└ $.xpath is rw = .XML::XPath @9
  ├ $.document = .XML::Document §1
  └ %.registered-namespaces is rw = {0} @11
-----------------------
Foo is Bar

(免责声明:我今天在我的代码中遇到了这种行为,所以我把它写成了问答式的。欢迎其他答案。)。

顺便说一句,这里有 XML::Rabbit and Data::Dump::Tree.

的链接

它是 lazy,就像 Perl 6 中的许多东西一样。换句话说,除非您要求,否则它不会故意浪费时间弄清楚 foo 属性是什么。这是一种优化,可避免消耗计算资源,除非您需要它们。

如果在调用 foo 方法后转储数据结构,您会看到它填充在数据转储中:

use XML::Rabbit;
use Data::Dump::Tree;

class RunInfo does XML::Rabbit::Node {
    has $.foo is xpath("/Foo");
}

sub MAIN ( $file! ) {

    my $xml = RunInfo.new( file => $file );

    put "Foo is $xml.foo()";

    dump $xml;
}
Foo is Bar
.RunInfo @0
├ $.foo = Bar.Str
├ $.context is rw = .XML::Document @1
│ ├ $.version = 1.0.Str
│ ├ $.encoding = Nil
│ ├ %.doctype = {0} @2
│ ├ $.root = .XML::Element @3
│ │ ├ $.name is rw = Foo.Str
│ │ ├ @.nodes is rw = [1] @4
│ │ │ └ 0 = .XML::Text @5
│ │ │   ├ $.text = Bar.Str
│ │ │   └ $.parent is rw = .XML::Element §3
│ │ ├ %.attribs is rw = {0} @7
│ │ ├ $.idattr is rw = id.Str
│ │ └ $.parent is rw = .XML::Document §1
│ ├ $.filename = example.xml.Str
│ └ $.parent is rw = Nil
└ $.xpath is rw = .XML::XPath @9
  ├ $.document = .XML::Document §1
  └ %.registered-namespaces is rw = {0} @11

这不是 Perl 6 内置功能的结果,而是 XML::Rabbit 模块的结果。

该模块提供 is xpath 特征,并确保在 class 组合时,任何应用了该特征的属性都将其访问器方法覆盖为自定义方法。

自定义访问器方法在第一次调用时计算并设置属性的值,在后续调用中只需 returns 现在已经存储在属性中的值。

自定义访问器方法实现如下(摘自the module's source code,省略部分)

method (Mu:D:) {
    my $val = $attr.get_value( self );
    unless $val.defined {
        ...
        $val = ...;
        ...
        $attr.set_value( self, $val );
    }
    return $val;
}

这里,$attr就是Attribute object corresponding to the attribute, and was retrieved prior to installing the method using the Meta-Object Protocol (MOP)


Data::Dump::Tree 模块不使用访问器方法获取属性值,而是直接使用 MOP 读取它。

因此,如果由于尚未调用访问器而尚未设置,它会将属性的值视为 Nil