7

我正在做这样的传递引用:

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因为它很丑。

4

4 回答 4

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修改了它的参数。

于 2010-03-17T18:22:45.477 回答
3

有几种方法可以做到这一点。将标量 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 将参数作为引用传递给所有函数的事实。的元素@_实际上是调用子例程时参数列表中的值的别名。通过更改$_[0]in foo(),您实际上将第一个参数更改为foo()

第二次通过 ref 方法使用这样一个事实,即使用&sigil 而没有 parens 调用的 sub 获取@_其调用者的数组。否则它是相同的。

更新:我刚刚注意到您希望避免$_[0]. 如果需要,您可以在 repl 中执行此操作:

sub repl {
    for my $line( $_[0] ) {
        $line = 'new value';
    }
}
于 2010-03-17T18:20:34.200 回答
3

 

sub repl {
    my $line = \$_[0];     # or: my $line = \shift
    $$line = "new value";
}
于 2010-03-17T18:34:58.760 回答
0

我认为local在这种情况下使用创建别名没有任何问题。

动态作用域当然是一个强大的特性,但只要你意识到副作用(新值在从其作用域调用的函数中可见,如果同名词法在作用域内,它就无法本地化, ...) 那么它是对已经满溢的 Perl 工具箱的有用补充。

Perl 文档中有关警告的主要原因local是防止人们无意中使用它,而不是my简化从 perl4 的过渡。但肯定local有有用的时候,这就是其中之一。

使用for创建别名也是一种选择,但我发现其明确的语法local意图更清晰。如果性能是一个问题,它也会更快一些。

于 2010-03-17T20:54:57.283 回答