我想写一个像这样的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_) = @_;
(即重命名麻烦的变量)。
还有其他解决方案吗?
答案 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
也会更好。