我正在做像这样的传递:
use strict;
use warnings;
sub repl {
local *line = \$_[0]; our $line;
$line = "new value";
}
sub doRepl {
my ($replFunc) = @_;
my $foo = "old value";
$replFunc->($foo);
print $foo; # prints "new value";
}
doRepl(\&repl);
有更清洁的方法吗?
原型不起作用,因为我正在使用函数引用(相信我有充分的理由使用函数引用)。
我也不想在$_[0]
中的任何地方使用repl
因为它很难看。
答案 0 :(得分:9)
你看过Data::Alias了吗?它允许您使用干净的语法创建词法范围的别名。
您可以使用它来创建像这样的传递引用语义:
use strict;
use warnings;
use Data::Alias;
sub foo {
alias my ($arg) = @_;
$arg++;
}
my $count = 0;
foo($count);
print "$count\n";
输出为1
,表示对foo
的调用修改了其参数。
答案 1 :(得分:3)
有几种方法可以做到这一点。明确地将标量引用传递给$foo
,或利用Perl的内置传递引用语义。
明确参考:
my $foo = "old value";
doRepl( \&repl, \$foo );
print $foo; # prints "new value";
sub repl {
my $line = shift;
$$line = "new value";
}
sub doRepl {
my ($replFunc, $foo) = @_;
$replFunc->($foo);
}
通过引用传递:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
$replFunc->(@_);
}
甚至更喜欢通过参考传递:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
&$replFunc;
}
第一个使用普通的perl硬引用来完成这项工作。
第一次通过ref方法使用Perl将所有函数的参数作为引用传递的事实。调用子例程时,@_
的元素实际上是参数列表中值的别名。通过更改$_[0]
中的foo()
,您实际上会将第一个参数更改为foo()
。
第二次通过ref方法使用这样一个事实,即使用&
sigil调用的sub并没有parens获取其调用者的@_
数组。否则它是相同的。
更新:我刚注意到您希望避免$_[0]
。如果您愿意,可以在repl中执行此操作:
sub repl {
for my $line( $_[0] ) {
$line = 'new value';
}
}
答案 2 :(得分:3)
sub repl {
my $line = \$_[0]; # or: my $line = \shift
$$line = "new value";
}
答案 3 :(得分:0)
我不认为在这种情况下使用local
创建别名有什么问题。
动态范围当然是一个强大的功能,但只要您了解副作用(在从作用域调用的函数中可以看到新值,如果同名的词法在范围内,则不能本地化,...)然后它是已经溢出的Perl工具箱的一个有用的补充。
Perl文档中关于local
的警告的主要原因是为了防止人们无意中使用它而不是my
,以便简化从perl4的过渡。但肯定有local
有用的时候,这就是一个。
使用for
创建别名也是一种选择,但我发现local
的显式语法更清晰。如果考虑性能,它也会快一点。