有没有更好的方法在 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 中通过引用传递?的主要内容,如果未能解决你的问题,请参考以下文章

在静态类方法中通过引用传递参数

有没有办法在函数调用中通过引用传递和通过值显式传递?

在 C++ 中通过引用传递对象

在 C# 中通过引用传递对象和对象列表

为啥在 PHP 中通过引用传递?

在 C# 中通过引用或值传递对象