有没有更好的方法在 Perl 中通过引用传递?
Posted
技术标签:
【中文标题】有没有更好的方法在 Perl 中通过引用传递?【英文标题】:Is there a better way to pass by reference in Perl? 【发布时间】:2011-01-28 17:05:37 【问题描述】:我正在做这样的传递引用:
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);
有没有更清洁的方法?
原型不起作用,因为我使用的是函数引用(相信我,使用函数引用是有充分理由的)。
我也不想在repl
的任何地方都使用$_[0]
,因为它很难看。
【问题讨论】:
【参考方案1】:我认为在这种情况下使用local
创建别名没有任何问题。
动态范围当然是一个强大的功能,但只要您意识到副作用(新值在从其范围调用的函数中可见,如果同名词汇在范围内,它就不能被本地化,...) 那么它是对已经溢出的 Perl 工具箱的有用补充。
Perl 文档中关于 local
的警告的主要原因是防止人们无意中使用它而不是 my
并简化从 perl4 的过渡。但是local
肯定会有用处,这就是其中之一。
使用for
创建别名也是一种选择,但我发现local
的显式语法在其意图上更加清晰。如果考虑性能,它也会更快一些。
【讨论】:
【参考方案2】:有几种方法可以做到这一点。将标量 ref 显式传递给 $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 将参数作为引用传递给所有函数的事实。 @_
的元素实际上是调用子例程时参数列表中的值的别名。通过在foo()
中更改$_[0]
,实际上您将第一个参数更改为foo()
。
第二个通过 ref 方法使用这样一个事实,即使用 &
sigil 且没有括号的子调用获取其调用者的 @_
数组。否则是相同的。
更新:我刚刚注意到您希望避免使用$_[0]
。如果需要,您可以在 repl 中执行此操作:
sub repl
for my $line( $_[0] )
$line = 'new value';
【讨论】:
【参考方案3】:
sub repl
my $line = \$_[0]; # or: my $line = \shift
$$line = "new value";
【讨论】:
@Sinan - 没想到会起作用。每天学习新东西。 规则参见perldoc.perl.org/perlref.html#Making-References "作为一种特殊情况,\(@foo)
返回对@foo
内容的引用列表,而不是对@foo
本身的引用。"
在标量上下文中,\(@foo)
是对包含@foo
中元素数量的标量值的引用[即,如\(scalar @foo)
]【参考方案4】:
你看过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
的调用修改了它的参数。
【讨论】:
不幸的是,我查看了文档的“实施”部分...... ack!我想这个模块有点像香肠……如果你不知道它们是怎么做的,那就更有趣了……:) @JoelFan:是的。这是一个非常“不要在家尝试”的模块:) 从“这个模块不使用源过滤器”开始,然后从那里走下坡路...... :)以上是关于有没有更好的方法在 Perl 中通过引用传递?的主要内容,如果未能解决你的问题,请参考以下文章