如果我已经有变量`$ a`和`$ b`

时间:2017-02-03 17:30:32

标签: arrays perl scope

我想写一个像这样的Perl子程序:

use List::MoreUtils qw{pairwise};
sub multiply {
    my ($a, $b) = @_;
    return [ pairwise {$a * $b} @$a, @$b ];
}

(乘法只是一个例子,我还要做其他的事情)

然而,这给了我荒谬的结果,因为Perl感到困惑,并尝试使用外部$a$b而不是列表项。

如果我在REPL中尝试此代码(例如reply):

0> use List::MoreUtils qw{pairwise};
1> my $a = [1, 2, 3];
…
2> my $b = [3, 2, 1];
…
3> pairwise {$a * $b} @$a, @$b;
Can't use lexical $a or $b in pairwise code block at reply input line 1.
4> sort {$a <=> $b} @$a;
"my $a" used in sort comparison at reply input line 1.
"my $b" used in sort comparison at reply input line 1.
$res[2] = [
  1,
  3,
  2
]

到目前为止,我的解决方案一直在用my ($a, $b) = @_;替换my ($a_, $b_) = @_;(即重命名麻烦的变量)。

还有其他解决方案吗?

2 个答案:

答案 0 :(得分:6)

好吧,首先关闭 - $a是一个糟糕的变量名称。你为什么这样做?单个字母几乎总是一个糟糕的选择,如果它只是一个迭代器或其他一些简单的用法,那就差不多了。

因此,解决方案将“不要称他们为$a$b”。

我的意思是,如果您确实不想使用其他名称:

sub multiply {
   return [ pairwise { $a * $b } @{$_[0]}, @{$_[1]} ];
}

但是你所做的事情确实突出了为什么命名空间冲突是个坏主意,因此在代码中使用$a$b作为实际变量会遇到麻烦。

我认为没有办法按照你想要的方式让它工作,即使你可以 - 你最终会得到一些令人困惑的代码。

我的意思是,这样的应该工作:

sub multiply {
   my ( $a, $b ) = @_;
   return [ pairwise { $::a * $::b } @$a, @$b ];
}

因为那时你明确地使用了包$a$b而不是词法。但请注意 - 如果从另一个包中导入它们将无法以相同的方式工作,而且通常会变得混乱。

但它很肮脏。 perlvar告诉你,你不应该这样做:

  

$一个

     

$ B

     

使用sort()时的特殊包变量,请参阅sort。由于这种特殊性,即使使用严格的“vars”编译指示,也不需要声明$ a和$ b(使用use vars或our())。如果您希望能够在sort()比较块或函数中使用它们,请不要使用$ a或$ b来词汇化它们。

在你进入“单字母变量名称”的领域之前,这几乎总是一个坏主意。

非常认真。是:

my ( $first, $second ) = @_;

其实那么糟糕?

答案 1 :(得分:3)

pairwise设置了其调用方包中的$a$b,因此您可以使用完全限定的变量名称。

假设此代码位于包main中,

use List::MoreUtils qw{pairwise};
sub multiply {
    my ($a, $b) = @_;
    return [ pairwise { $main::a * $main::b } @$a, @$b ];
}

或者,our创建一个词法变量,该变量使用相同名称的当前包变量别名,并且它将覆盖自最近的词法变量声明以来的my声明胜出。

use List::MoreUtils qw{pairwise};
sub multiply {
    my ($a, $b) = @_;
    return [ pairwise { our $a * our $b } @$a, @$b ];
}

第二种方法显然不如第一种方法脆弱,但你知道什么会更不脆弱吗?首先不要将$a$b声明为词法变量! :)只是使用不同的变量会简单得多。即使$A$B$x$y也会更好。