如果我可以按照shift,push和其他内置子程序的工作方式使用子程序,那么在我的脚本中会使很多事情变得更容易:它们都可以直接更改传递给它的变量而不需要返回更改。
当我尝试这样做时,变量会在某个时刻被复制,而我似乎只是在改变副本。我理解这对引用来说没问题,但它甚至发生在数组和哈希中,我觉得我只是将我正在处理的变量传递给sub,以便可以对它进行更多的工作:
@it = (10,11);
changeThis(@it);
print join(" ", @it),"\n"; #prints 10 11 but not 12
sub changeThis{
$_[2] = 12;
}
有办法做到这一点吗?我知道这不是最好的做法,但就我而言,这将非常方便。
答案 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;
}
(请注意,您必须在第一次调用之前预先声明您的潜艇或将子定义放在最前面。)