我正在寻找一种更有效的方法来编写perl中的这个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)
任何的想法?
如果你真的把密钥传递给它会更有效!我们让它同时成为一个左值子.
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)
比较流量affect和dive_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可以轻松扩展以支持混合数组/哈希结构.