我创建了这个简单的子程序。
public class StudentInfo {
....
@Override
public String toString() {
return studentName;
}
}
直到子例程从定义它的同一文件中使用才能正常工作。当我将其移动到某个包时,变量use List::Util qw(pairmap);
sub pairGroupBy(&@) {
my($irCode, @iaItems) = @_;
my %laResult = ();
pairmap {
my $lsKey = $irCode->();
if (!defined($lsKey)) {
die "Trying to pairGroup by nonexisting key '$lsKey'";
}
push @{$laResult{$lsKey}}, $a => $b;
} @iaItems;
return %laResult;
}
和$a
在$b
回调中变为未定义。
我从List::Util source code了解到这段代码可以解决问题:
$irCode->()
所以我以这种方式修改了我的子程序:
my $caller = caller;
local(*{$caller."::a"}) = \my $a;
local(*{$caller."::b"}) = \my $b;
但我需要使用use List::Util qw(pairmap);
sub pairGroupBy(&@) {
my($irCode, @iaItems) = @_;
my $caller = caller;
my %laResult = ();
pairmap {
no strict 'refs';
local(*{$caller."::a"}) = \$a; # <---- the line 96
local(*{$caller."::b"}) = \$b;
my $lsKey = $irCode->();
if (!defined($lsKey)) {
die "Trying to pairGroup by nonexisting key '$lsKey'";
}
push @{$laResult{$lsKey}}, $a => $b;
} @iaItems;
return %laResult;
}
行(List::Util source code不使用它)。否则会显示错误消息:
no strict 'refs';
我的问题是:如果在不使用Can't use string ("main::a") as a symbol ref while "strict refs" in use at /home/.../bin/SatFunc.pm line 96.
的情况下如何在来电者的上下文中定义$a
和$b
变量有更好的方法吗?
我希望我的功能的使用方式与pairmap,pairgrep等相同。
修改: @simbabque问了一个例子,该函数是如何使用的。所以这是一个例子:
no strict 'refs';
然后该函数返回此结构:
my %laHoH = (
aa => {
color => 'yellow',
item => 'sun',
active => 1
},
bb => {
color => 'blue',
item => 'sky',
active => 1
},
cc => {
color => 'green',
item => 'grass',
active => 0
},
dd => {
color => 'blue',
item => 'watter',
active => 1
}
);
my %laGrouped = pairGroupBy {
$b->{color}
} pairgrep {
$b->{active}
} %laHoH;
答案 0 :(得分:2)
我不确定你为什么会看到这个问题,但我怀疑你是否会过度思考问题。在像这样的虚拟上下文中使用pairmap
似乎是一个坏主意。
您是不是只是将数组转换为哈希值然后迭代它?
my %iaItemsHash = @iaItams;
while (my ($k, $v) = each %iaItemsHash) {
my $lsKey = $irCode->();
if (!defined($lsKey)) {
die "Trying to pairGroup by nonexisting key '$lsKey'";
}
push @{$laResult{$lsKey}}, $k => $v;
}
更新:根据您的评论,我已重新阅读您的原始问题,并发现您正在讨论通过$irCode->()
电话访问变量。
我的解决方案的问题是$k
和$v
是词汇变量,因此,它们的词法范围之外是不可用的(这通常被视为一个特征!)解决方案是采用良好的编程习惯,并将值作为参数发送到子程序中。
答案 1 :(得分:1)
有没有更好的方法如何在调用者的上下文中定义
$a
和$b
变量而不使用no strict 'refs';?
你问我们如何执行符号解除引用,同时要求Perl阻止你进行符号表示。没有理由这样做。如果您想执行符号解除引用,请不要让Perl阻止您执行此操作。
即使Perl没有抓住你这样做(即如果你设法找到一种不触发use strict qw( refs );
的方法),你仍然会使用符号解除引用!你只是骗自己和读者。
相反,最好记录您正在做的事情。使用no strict qw( refs );
表示您正在使用某些use strict qw( refs );
假设阻止。
以下用于构建与代码相同结构的方法更不浪费:
my %laGrouped;
for my $key (keys(%laHoH)) {
my $rec = $laHoH{$key};
next if !$rec->{active};
push @{ $laGrouped{ $rec->{color} } }, $key, $rec;
}
但是我们也要改进结构。以下方法产生了一种更易于使用的结构:
my %laGrouped;
for my $key (keys(%laHoH)) {
my $rec = $laHoH{$key};
next if !$rec->{active};
$laGrouped{ $rec->{color} }{$key} = $rec;
}
如果你发现自己使用pairGroupBy
,你可能在某个地方出错了。但是出于教育目的,这里有更好的实施方式:
sub pairGroupBy(&@) {
my $cb = shift;
my $caller = caller;
my $ap = do { no strict 'refs'; \*{ $caller.'::a' } }; local *$ap;
my $bp = do { no strict 'refs'; \*{ $caller.'::b' } }; local *$bp;
my %groups;
while (@_) {
*$ap = \shift;
*$bp = \shift;
my $group = $cb->();
push @{ $groups{$group} }, $a, $b;
}
return %groups;
}