Perl 通过预定义的哈希将访问器添加到类::XSAccessor?
考虑以下示例:Perl 通过预定义的哈希将访问器添加到类::XSAccessor?,perl,hash,accessor,Perl,Hash,Accessor,考虑以下示例: use 5.010; use Data::Dumper; { package MyTestPck; use Data::Dumper; use Tie::IxHash; sub ordered_hash { # http://stackoverflow.com/a/3001400/277826 tie my %hash => 'Tie::IxHash'; %hash = @_; \%hash } my $fields = o
use 5.010;
use Data::Dumper;
{
package MyTestPck;
use Data::Dumper;
use Tie::IxHash;
sub ordered_hash { # http://stackoverflow.com/a/3001400/277826
tie my %hash => 'Tie::IxHash';
%hash = @_;
\%hash
}
my $fields = ordered_hash(
(map { $_ => $_ } (qw(
varA
varB
varC
)))
);
print Dumper($fields);
use Class::XSAccessor
accessors => {
%{$fields}
};
sub new {
my $class = shift;
my @set_arr = @_; # the rest
my $ic = 0; my $self = {};
bless $self, $class;
for my $k (keys %{$fields}) {
my $fld = $fields->{$k};
my $val = $set_arr[$ic];
print("k $k fld $fld ic/val $ic $val\n");
$self->$fld($val);
$ic++;
}
return $self;
}
1;
}
my $pcktestobj = MyTestPck->new((10, 20, 30));
print Dumper($pcktestobj);
如果我按原样运行它;代码在以下情况下失败:
$perl/tmp/test.pl
$VAR1={
“瓦拉”=>“瓦拉”,
“varB”=>“varB”,
“varC”=>“varC”
};
k瓦拉fld瓦拉ic/val 0 10
无法通过/tmp/test.pl第34行的包“MyTestPck”找到对象方法“varA”。
但是,如果将代码的中间部分替换为:
...
use Class::XSAccessor
accessors => ordered_hash(
(map { $_ => $_ } (qw(
varA
varB
varC
)))
);
...
。。。然后输出如预期的那样:
$perl/tmp/test.pl
$VAR1={
“瓦拉”=>“瓦拉”,
“varB”=>“varB”,
“varC”=>“varC”
};
k瓦拉fld瓦拉ic/val 0 10
k varB fld varB ic/val 120
k varC fld varC ic/val 2 30
$VAR1=祝福({
“varC”=>30,
“varB”=>20,
“瓦拉”=>10
}“MyTestPck”);
因此,显然,我无法通过预定义的哈希设置访问器,如use Class::XSAccessor accessors=>{%{$fields}代码>-显然我必须内联指定访问器哈希
但这是为什么呢?有没有什么东西应该提醒我注意这种行为?是否有一种方法可以将预定义字段(如我在第一个示例中所打算的)用于Class::XSAccessor
?use
语句在编译时执行,但直到运行时才会填充哈希。看看这个例子:
my $x = {}; # this statement is executed **SECOND**
use strict; # this statement is executed **FIRST**
因此,您无法在上面的use
语句中有效地使用$x
变量<代码>$x
尚未定义
幸运的是,use
语句可以很容易地分解为一个require
,然后是一个import
。每种情况都发生在运行时。因此,请尝试替换此:
use Class::XSAccessor
accessors => {
%{$fields}
};
为此:
require Class::XSAccessor;
Class::XSAccessor->import( accessors => $fields );
另一种方法是强制在编译时填充
$fields
。这应该行得通,但不太好看:
my $fields;
BEGIN {
$fields = ordered_hash(
(map { $_ => $_ } (qw(
varA
varB
varC
)))
);
print Dumper($fields);
};
use Class::XSAccessor
accessors => {
%{$fields}
};
非常感谢,@tobynk-不知道
use
语句的执行顺序;使用require
和BEGIN
的绝妙技巧!!干杯也许有必要尝试理解脚本是如何工作的。一开始它看起来很混乱,但一旦它在您的脑海中“点击”,您就再也不会被运行时与编译时的对比绊倒了。