2017-08-14 14 views
5

Với này đơn giản đi tập tin XML:Tại sao thuộc tính đối tượng của tôi không được điền?

<Foo>Bar</Foo> 

Và mã này được chiết xuất giá trị cho các phần tử 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()"; 
} 

Bạn sẽ thấy rằng giá trị cho fooNil, mặc dù đầu ra hiển thị 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 

(Disclaimer: Tôi đã xem qua hành vi này ngày hôm nay trong mã của tôi, vì vậy tôi đã viết nó lên Q & Một phong cách. Câu trả lời khác chào đón.).

Nhân tiện, đây là các liên kết đến XML::RabbitData::Dump::Tree.

Trả lời

2

Đây không phải là kết quả của một được xây dựng trong Perl 6 tính năng, nhưng thay vì một cái gì đó các mô-đun XML::Rabbit.

Mô-đun đó cung cấp đặc điểm is xpath và đảm bảo rằng tại thời điểm thành phần lớp, bất kỳ thuộc tính nào có đặc điểm được áp dụng đều được phương thức truy cập của nó ghi đè bằng một tùy chỉnh.

Phương thức truy cập tùy chỉnh tính toán và đặt giá trị cho thuộc tính lần đầu tiên được gọi và cuộc gọi tiếp theo chỉ trả về giá trị hiện đã được lưu trữ trong thuộc tính.

Phương pháp tùy chỉnh accessor được thực hiện như sau (lấy từ the module's source code với các bộ phận elided):

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

Ở đây, $attr là đối tượng Attribute tương ứng với thuộc tính, và được lấy ra trước khi cài đặt phương pháp sử dụng Meta-Object Protocol (MOP).


Các Data::Dump::Tree mô-đun, đến lượt nó, không sử dụng các phương pháp accessor để lấy giá trị của các thuộc tính, mà đúng hơn là đọc nó trực tiếp bằng cách sử dụng MOP.

Do đó, nó thấy giá trị của thuộc tính là Nil nếu chưa được đặt vì người truy cập chưa được gọi.

4

Đó là lazy, giống như nhiều thứ trong Perl 6. Nói cách khác, nó cố ý không lãng phí thời gian để tìm ra thuộc tính foo trừ khi bạn yêu cầu. Đây là một tối ưu hóa để tránh tiêu thụ tài nguyên tính toán trừ khi bạn cần chúng.

Nếu bạn đổ cấu trúc dữ liệu sau khi gọi phương thức foo, bạn sẽ thấy rằng nó được phổ biến ở các bãi chứa dữ liệu:

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 
Các vấn đề liên quan