为什么没有填充我的对象属性?
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
。
鉴于此过于简化的 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
。