6

我做通通过引用这样的:有没有更好的方式在Perl中通过引用传递?

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

回答

9

你看了看Data::Alias?它允许您使用干净的语法创建词法范围的别名。

您可以使用它来创建传递by-reference语义是这样的:

use strict; 
use warnings; 

use Data::Alias; 

sub foo { 
    alias my ($arg) = @_; 
    $arg++; 
} 

my $count = 0; 

foo($count); 

print "$count\n"; 

输出为1,表明调用foo修改其参数。

+0

不幸的是,我看着文档的“实施”部分... ack!我猜这个模块有点像香肠......如果你不知道它们是如何制作的,那么它会更令人愉快...... :) – JoelFan 2010-03-18 16:22:31

+0

@JoelFan:yup。这是一个“不要在家里尝试这个”模块:) – 2010-03-18 16:37:12

+0

开始“这个模块不使用源过滤器”,并从那里下坡... :) – JoelFan 2010-03-18 20:01:30

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将参数作为引用传递给所有函数的事实。当调用子例程时,@_的元素实际上是参数列表中值的别名。通过改变foo()中的$_[0],您实际上将第一个参数更改为foo()

第二次通过ref方法使用的事实是,调用& sigil并且没有parens调用的子实例获取调用者的@_数组。否则它是相同的。

更新:我只是注意到你想避免$_[0]。如果你愿意,你可以在repl中这样做:

sub repl { 
    for my $line($_[0]) { 
     $line = 'new value'; 
    } 
} 
+0

谢谢...良好的信息,但我想要“隐式”通过参考文献 – JoelFan 2010-03-17 18:48:49

3

 

sub repl { 
    my $line = \$_[0];  # or: my $line = \shift 
    $$line = "new value"; 
} 
+0

或'我的($行)= \(@_);' – 2010-03-17 18:40:07

+0

@Sinan - 不会猜测会奏效。每天学习新东西。 – mob 2010-03-17 19:28:04

+1

rule参见http://perldoc.perl.org/perlref.html#Making-References“作为一种特殊情况,'\(@ foo)'返回'@ foo'内容的引用列表,而不是引用到'@ foo'本身。“ – 2010-03-17 19:46:01

0

我不认为这有什么错误使用local建立在这种情况下别名。

动态范围当然是一个强大的功能,但只要您意识到副作用(新值在从其范围调用的函数中可见,如果同一名称的词汇在范围内,本地化......),那么它对已经溢出的Perl工具箱来说是一个有用的补充。

Perl文档中有关local的警告的主要原因是为了防止人们无意中使用它而不是my并缓解从perl4过渡。但是有一些时候local是有用的,这是一个。

使用for来创建您的别名也是一个选项,但我发现明确的语法与local明确的意图。如果性能受到关注,速度也会更快。

相关问题