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

now*_*wox 1 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;
Run Code Online (Sandbox Code Playgroud)

并且预期的结果是:

$VAR1 = {
          'foo' => {
                     'bar' => {
                                'baz' => 42
                              },
                     'babel' => 'fish'
                   }
        };
Run Code Online (Sandbox Code Playgroud)

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

%hash{ @keys } = 42;
Run Code Online (Sandbox Code Playgroud)

任何的想法?

ike*_*ami 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;
Run Code Online (Sandbox Code Playgroud)

这种实现有两个额外的好处.

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

print(dive_val($hash, @keys), "\n");
Run Code Online (Sandbox Code Playgroud)

其次,它将自动生成其第一个参数.

my $hash;
dive_val($hash, @keys) = 42;
Run Code Online (Sandbox Code Playgroud)

这个功能已经存在的数据::潜水员DiveVal.

use Dive::Val qw( DiveVal );

DiveVal(\%hash, map \$_, @keys) = 42;
Run Code Online (Sandbox Code Playgroud)

比较流量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]}
    
    Run Code Online (Sandbox Code Playgroud)
  • 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
    
    Run Code Online (Sandbox Code Playgroud)

dive_val的方法更纯粹.

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

  • 哇,我需要时间来消化这个.精彩的例子谢谢你.你能解释一下你在这里做的更多吗? (2认同)