gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 16:19:47 25 4
gpt4 key购买 nike

前几天我注意到 - 在更改散列中的值时 - 当您在 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};

这是可以理解的,因为 SO 上的许多帖子都使用该成语为哈希创建本地名称,而没有解释它实际上是在制作副本。

在 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' 的替换。对于 'hash'作为标识符的名称。
%{hash}
${hash}{key}
@{hash}{qw(a b)}

使用元素时,您还可以使用取消引用箭头:
$hash->{key}  # exactly the same as $$hash{key}

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

所以总结一下,任何时候你写这样的东西:
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

关于perl - 关于在 Perl 中正确使用取消引用的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6740091/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com