Perl:在调用者上下文中定义变量

时间:2017-12-21 11:27:52

标签: perl

我创建了这个简单的子程序。

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变量有更好的方法吗?

我希望我的功能的使用方式与pairmappairgrep等相同。

修改: @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;

2 个答案:

答案 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;
}