关于 Perl 中取消引用正确使用的困惑

2023-12-28

前几天我注意到,在更改散列中的值时,当您在 Perl 中取消引用散列时,实际上是在复制该散列。为了确认我写了这个快速的小脚本:

#! perl
use warnings;
use strict;

my %h = ();
my $hRef = \%h;
my %h2 = %{$hRef};
my $h2Ref = \%h2;

if($hRef eq $h2Ref) {
  print "\n\tThey're the same $hRef $h2Ref";
}
else {
  print "\n\tThey're NOT the same $hRef $h2Ref";
}
print "\n\n";

输出:

    They're NOT the same HASH(0x10ff6848) HASH(0x10fede18)

这让我意识到我的某些脚本中可能存在某些地方的行为不符合预期。为什么会这样呢?如果您传递或返回散列,则更自然地假设取消引用散列将允许我更改被取消引用的散列的值。相反,我只是到处复制,没有任何真正的需要/理由,除了使语法更加明显之外。

我意识到,直到现在我才注意到这一点,这表明它可能没什么大不了的(就需要修复我的所有脚本而言 - 但未来很重要)。我认为很少会看到明显的性能差异,但这并不能改变我仍然感到困惑的事实。

这是 Perl 设计的吗?是否有一些我不知道的明确原因?或者这是刚刚知道的,而您(作为程序员)期望知道并相应地编写脚本?


问题是您正在复制要在这一行中使用的哈希值:

my %h2 = %{$hRef};

这是可以理解的,因为这里的许多帖子都使用这个习惯用法来为哈希创建本地名称,而没有解释它实际上是在制作副本。

在 Perl 中,哈希是复数值,就像数组一样。这意味着在列表上下文中(例如分配给哈希时得到的),聚合将被分解为其内容列表。然后,这个对列表被组装成一个新的散列,如图所示。

您想要做的是直接使用参考。

for (keys %$hRef) {...}
for (values %$href) {...}

my $x = $href->{some_key};
# or
my $x = $$href{some_key};

$$href{new_key} = 'new_value';

当使用普通散列时,您有一个印记,它可以是%当谈论整个哈希时,$当谈论单个元素时,并且@当谈论切片时。每个符号后面都跟着一个标识符。

 %hash          # whole hash
 $hash{key}     # element
 @hash{qw(a b)} # slice

使用名为的参考$href只需替换字符串hash在上面的代码中$href。换句话说,$href是标识符的完整名称:

%$href          # whole hash
$$href{key}     # element
@$href{qw(a b)} # slice

其中每一个都可以写成更详细的形式:

%{$href}
${$href}{key}
@{$href}{qw(a b)}

这又是字符串的替换'$href' for 'hash'作为标识符的名称。

%{hash}
${hash}{key}
@{hash}{qw(a b)} 

在使用元素时,您还可以使用取消引用箭头:

$hash->{key}  # exactly the same as $$hash{key}

但我更喜欢双印记语法,因为它类似于整个聚合和切片语法,以及正常的非引用语法。

总而言之,任何时候你写这样的东西:

my @array = @$array_ref;
my %hash  = %$hash_ref;

您将复制每个聚合的第一层。直接使用取消引用语法时,您将处理实际值,而不是副本。


如果您想要哈希的真实本地名称,但想要处理相同的哈希,您可以使用local关键字来创建别名。

 sub some_sub {
    my $hash_ref = shift;
    our %hash; # declare a lexical name for the global %{__PACKAGE__::hash}
    local *hash = \%$hash_ref;
        # install the hash ref into the glob
        # the `\%` bit ensures we have a hash ref

    # use %hash here, all changes will be made to $hash_ref

 }  # local unwinds here, restoring the global to its previous value if any

这是纯粹的 Perl 别名方式。如果你想使用my变量来保存别名,您可以使用该模块Data::Alias

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于 Perl 中取消引用正确使用的困惑 的相关文章

随机推荐