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

时间:2017-08-14 16:06:34

标签: perl6

鉴于这个过于简化的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

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

顺便说一下,这里有指向XML::RabbitData::Dump::Tree的链接。

2 个答案:

答案 0 :(得分:4)

它是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

答案 1 :(得分:2)

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

该模块提供is xpath特征,并确保在类组合时,任何具有该特征的属性都会使用自定义方法覆盖其访问方法。

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

自定义访问器方法实现如下(取自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对象,并在使用Meta-Object Protocol (MOP)安装方法之前检索。

反过来, Data::Dump::Tree 模块不会使用访问器方法来获取属性的值,而是使用MOP直接读取它。 / p>

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