在一条指令中影响多级散列的值

时间:2015-06-10 20:05:54

标签: perl hash

我正在寻找一种更有效的方法来在中编写此affect子例程:

#!/usr/bin/perl
use 5.010;
use strict;

my @keys = qw/foo bar baz/;
my %hash = ( foo => {babel => 'fish'} );

affect (\%hash, 42);

sub affect {
   my $ref = shift;
   $ref = $ref->{$keys[$_]} //= {} for (0.. $#keys - 1);
   $ref->{$keys[$#keys]} = shift;
}

use Data::Dumper;
print Dumper \%hash;

预期结果:

$VAR1 = {
          'foo' => {
                     'bar' => {
                                'baz' => 42
                              },
                     'babel' => 'fish'
                   }
        };

我正在考虑这样的事情,但显然它不能像这样工作:

%hash{ @keys } = 42;

有什么想法吗?

1 个答案:

答案 0 :(得分:5)

如果您真正传递密钥会更有效!我们让它同时成为一个左值子。

sub dive_val :lvalue {
   my $p = \shift;
   $p = \( $$p->{$_} ) for @_;
   $$p
}

my %hash;
dive_val(\%hash, qw( foo babel )) = 'fish';
dive_val(\%hash, @keys) = 42;

此实施有两个额外的好处。

首先,您可以使用它来查看数据结构。

print(dive_val($hash, @keys), "\n");

其次,它会自动生成第一个参数。

my $hash;
dive_val($hash, @keys) = 42;

此功能已作为Data::DiverDiveVal存在。

use Dive::Val qw( DiveVal );

DiveVal(\%hash, map \$_, @keys) = 42;

affectdive_val的流量比较:

  • affect

    $ref是对哈希的引用。

    Pre-loop:            $ref references %hash
    After loop pass 0:   $ref references %{ $hash{$key[0]} }
    After loop pass 1:   $ref references %{ $hash{$key[0]}{$key[1]} }
    Post loop uses:      $ref->{$key[2]}
    
  • dive_val

    $p是对标量的引用。

    Pre-loop:            $p references $hash
    After loop pass 0:   $p references $hash->{$key[0]}
    After loop pass 1:   $p references $hash->{$key[0]}{$key[1]}
    After loop pass 2:   $p references $hash->{$key[0]}{$key[1]}{$key[2]}
    Post loop uses:      $$p
    

dive_val的方法更纯粹。

  • 在解除引用之前不需要创建哈希(与在前一个循环传递中创建哈希的affect不同)。
  • 实际上,标量根本不需要哈希。这意味着可以轻松扩展dive_val以支持混合数组/哈希结构。
  • 没有必要特别对待root(如果你想接受一个可能未定义的参数)。
  • 没有必要特别对待最后一把钥匙。