2017-08-14 63 views
5

鉴于这种过于简单的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()"; 
} 

你会看到,fooNil,即使输出显示为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 &样式。其他答案欢迎。)。

顺便提一下,这里有链接到XML::RabbitData::Dump::Tree

回答

2

这是不是一个结果内置Perl 6功能,而是模块所具有的功能。

该模块提供了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。

因此,如果尚未设置该属性的值,则该属性值为Nil,因为该存取器尚未被调用。

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 
相关问题