问题描述
我试图弄清楚Perl子例程及其工作方式.从 perlsub 中,我了解到子例程是按引用调用的,并且子例程是赋值的(例如my(@copy) = @_;
)将其转化为按值致电.
I'm trying to figure out Perl subroutines and how they work.From perlsub I understand that subroutines are call-by-reference and that an assignment (like my(@copy) = @_;
) is needed to turn them into call-by-value.
在下面,我看到change
被称为引用,因为"a"和"b"被更改为"x"和"y".但是我对为什么不使用额外的元素"z"扩展数组感到困惑?
In the following, I see that change
is called-by-reference because "a" and "b" are changed into "x" and "y". But I'm confused about why the array isn't extended with an extra element "z"?
use strict;
use Data::Dumper;
my @a = ( "a" ,"b" );
change(@a);
print Dumper(\@a);
sub change
{
@_[0] = "x";
@_[1] = "y";
@_[2] = "z";
}
输出:
$VAR1 = [
'x',
'y'
];
在下面,我传递一个散列而不是一个数组.为什么键不能从"a"更改为"x"?
In the following, I pass a hash instead of an array. Why isn't the key changed from "a" to "x"?
use strict;
use Data::Dumper;
my %a = ( "a" => "b" );
change(%a);
print Dumper(\%a);
sub change
{
@_[0] = "x";
@_[1] = "y";
}
输出:
$VAR1 = {
'a' => 'y'
};
我知道 real 解决方案是使用\@
通过引用传递数组或哈希,但是我想准确地了解这些程序的行为.
I know the real solution is to pass the array or hash by reference using \@
, but I'd like to understand the behaviour of these programs exactly.
推荐答案
Perl始终通过引用传递.只是有时调用者会传递临时标量.
Perl always passes by reference. It's just that sometimes the caller passes temporary scalars.
您必须意识到的第一件事是,subs的参数可以是一个,并且只能是一件事:标量列表.*无法将数组或哈希传递给它们.对数组和散列进行求值,并返回其内容列表.那意味着
The first thing you have to realise is that the arguments of subs can be one and only one thing: a list of scalars.* One cannot pass arrays or hashes to them. Arrays and hashes are evaluated, returning a list of their content. That means that
f(@a)
与**
f($a[0], $a[1], $a[2])
Perl通过引用传递.具体来说,Perl将每个参数都别名为@_
的元素.修改元素@_
会更改$a[0]
等返回的标量,因此将修改@a
的元素.
Perl passes by reference. Specifically, Perl aliases each of the arguments to the elements of @_
. Modifying the elements @_
will change the scalars returned by $a[0]
, etc. and thus will modify the elements of @a
.
重要的第二件事是数组或哈希元素的键确定该元素在结构中的存储位置.否则,$a[4]
和$h{k}
将需要查看数组或哈希的每个元素以找到所需的值.这意味着密钥不可修改.移动值需要使用新键创建一个新元素,并删除旧键处的元素.
The second thing of importance is that the key of an array or hash element determines where the element is stored in the structure. Otherwise, $a[4]
and $h{k}
would require looking at each element of the array or hash to find the desired value. This means that the keys aren't modifiable. Moving a value requires creating a new element with the new key and deleting the element at the old key.
这样,每当您获得数组或哈希的键时,就会获得键的副本.可以这么说,是新鲜的标量.
As such, whenever you get the keys of an array or hash, you get a copy of the keys. Fresh scalars, so to speak.
回到问题,
f(%h)
与**
f(
my $k1 = "a", $h{a},
my $k2 = "b", $h{b},
my $k2 = "c", $h{c},
)
@_
仍然是%h
返回的值的别名,但是其中一些只是用于保存键的临时标量.更改这些设置将不会产生持久的影响.
@_
is still aliased to the values returned by %h
, but some of those are just temporary scalars used to hold a key. Changing those will have no lasting effect.
*—一些内置函数(例如grep
)更像流控制语句(例如while
).它们具有自己的解析规则,因此不仅限于传统的子模型.
* — Some built-ins (e.g. grep
) are more like flow control statements (e.g. while
). They have their own parsing rules, and thus aren't limited to the conventional model of a sub.
**—原型可以影响参数列表的求值方式,但仍会生成标量列表.
** — Prototypes can affect how the argument list is evaluated, but it will still result in a list of scalars.
这篇关于Perl子例程是按引用调用还是按值调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!