直接将参数更改为子例程

时间:2011-06-20 13:12:32

标签: perl

如果我可以按照shift,push和其他内置子程序的工作方式使用子程序,那么在我的脚本中会使很多事情变得更容易:它们都可以直接更改传递给它的变量而不需要返回更改。

当我尝试这样做时,变量会在某个时刻被复制,而我似乎只是在改变副本。我理解这对引用来说没问题,但它甚至发生在数组和哈希中,我觉得我只是将我正在处理的变量传递给sub,以便可以对它进行更多的工作:

@it = (10,11);
changeThis(@it);
print join(" ", @it),"\n"; #prints 10 11 but not 12

sub changeThis{
    $_[2] = 12;
}

有办法做到这一点吗?我知道这不是最好的做法,但就我而言,这将非常方便。

3 个答案:

答案 0 :(得分:10)

这就是原型的用途:

#!/usr/bin/perl

use strict;
use warnings;

sub changeThis(\@);     # the argument will be seen as an array ref (prototype must come before the call!)

my @it = (10,11);  
changeThis @it;         # even when called with an array
print join(" ", @it),"\n"; #prints 10 11 12

sub changeThis(\@)
  { my( $ar)= @_; $ar->[2]= 12; }

有关详细信息,请参阅http://perldoc.perl.org/perlsub.html#Prototypes

这不是一个真正流行的方法,传递实际的数组引用可能是一个更好的选择,但涉及的魔法更少。

答案 1 :(得分:5)

问题是子调用将变量扩展为值列表,这些值被传递给子例程。即传递副本,而不是变量本身。您的子呼叫等于:

changeThis(11, 12);

如果您想更改原始数组,请改为传递参考:

use strict;
use warnings;

my @it = (10,11);
changeThis(\@it);
print join(" ", @it),"\n";

sub changeThis{
    my $array = shift;
    $$array[2] = 12;
}

此外,@_[2]会向您发出警告:

Scalar value @_[2] better written as $_[2]

如果你use warnings,你当然应该这样做。除非你确切知道自己在做什么,否则没有充分的理由不打开警告和严格警告。

答案 2 :(得分:2)

如前面的答案所示,您应该使用传递给子例程的引用。 此外,如果您想通过documentation for Prototypes

阅读,也可以使用隐式引用
sub changeThis(\@);

@it = (10,11);
changeThis @it;
print join(" ", @it),"\n"; #prints 10 11 12

sub changeThis(\@){
    $_[0][2] = 12;
}

(请注意,您必须在第一次调用之前预先声明您的潜艇或将子定义放在最前面。)