Perl 子程序是按引用调用还是按值调用? [英] Are Perl subroutines call-by-reference or call-by-value?

查看:26
本文介绍了Perl 子程序是按引用调用还是按值调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试弄清楚 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'
        ];

在下面,我传递一个散列而不是一个数组.为什么key没有从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'
};

我知道真正的解决方案是使用 @ 通过引用传递数组或散列,但我想准确了解这些程序的行为.

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 子程序是按引用调用还是按值调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆