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
的绝妙技巧!!干杯也许有必要尝试理解脚本是如何工作的。一开始它看起来很混乱,但一旦它在您的脑海中“点击”,您就再也不会被运行时与编译时的对比绊倒了。