这种代码有什么意义?

ask*_*ker 9 perl

{%{$self->param}}
Run Code Online (Sandbox Code Playgroud)

它确实散列扩展,然后创建另一个散列引用.

但是不{%{$self->param}}一样$self->param吗?为什么代码打扰这个伎俩呢?

mus*_*iKk 15

它复制哈希.请考虑以下代码段:

use Data::Dumper;

my $foo = { a => 1, ar => [1] };
my $bar = {%$foo};

$bar->{b} = 2;
push @{$bar->{ar}}, 4;

print Dumper $foo;
print Dumper $bar;
Run Code Online (Sandbox Code Playgroud)

它打印

$VAR1 = {
          'a' => 1,
          'ar' => [
                    1,
                    4
                  ]
        };
$VAR1 = {
          'a' => 1,
          'b' => 2,
          'ar' => [
                    1,
                    4
                  ]
        };
Run Code Online (Sandbox Code Playgroud)

因此,您可以看到副本很浅:即使它们是引用,也会复制标量.引用的对象是相同的(在此示例中引用的数组ar).

  • 不要忘记提到这会产生一个**浅**(不是**深**)副本 - 例如,引用本身的哈希值将保留在新副本中的原始位置,而不是被复制以及原始哈希 (2认同)

Bla*_*iev 8

虽然这两个{%{$self->param}}$self->param是一个哈希的引用,他们并不指存储在同一个位置的哈希值.

第一个表达式取消引用$self->param哈希,并返回对匿名哈希的引用.在外括号内,%{$self->param}实际上是临时展开和复制,然后返回对此临时副本的引用,而不是旧哈希.


yko*_*yko 8

此代码实际上创建了一个副本哈希(键和值的浅表副本,但不是深层副本),返回引用并返回对它的引用.

如果某个子返回引用哈希并且您更改了某些内容,则实际上您正在更改原始哈希中的值.为避免这种情况,我们有时需要在进行任何更改之前复制整个哈希(或数组).

这是一个例子:

sub get_hashref {
    my $hashref = shift;
    return $hashref;
}

my %hash = (foo => 'bar');

my $ref = get_hashref(\%hash);
$ref->{foo} = 'baz'; # Changes 'foo' value in %hash
print "Original 'foo' now is: $hash{foo}\n"; # 'baz'
print "Ref's 'foo' now is: $ref->{foo}\n";   # 'baz'

# But!

$ref = {%{ get_hashref(\%hash) }};
$ref->{foo} = 42; # No changes in %hash
print "Original 'foo' now is: $hash{foo}\n"; # 'baz'
print "Ref's 'foo' now is: $ref->{foo}\n";   # '42'
Run Code Online (Sandbox Code Playgroud)

为了更好地理解,{%{ $self->param }}可以扩展到:

my $ref = $self->param; # Ref to original hash
my %copy = %{$ref}; # Copies keys and values to new hash
my $ref_to_copy = {%copy}; # get ref to it
Run Code Online (Sandbox Code Playgroud)

如果您需要哈希但不参考它,您也可以省略最后一步.