我如何存储哈希路径将它们重复使用



,可以说我在哈希中嵌套了大量元素(来自JSON(。我想为他们准备好和固定器。例如:

sub set_element_x{
    my ($self, $hash_ref, $value) = @_;
    $hash_ref->{'path1'}->{'path2'}->{'x'} = $value;
    return;
}
sub get_element_x{
    my ($self, $hash_ref, $value) = @_;
    return $hash_ref->{'path1'}->{'path2'}->{'x'};
}

是否有一种标准的方式来处理这条路,以防您只需要更改它们,以防JSON结构发生变化?

我想添加更多信息,因为我认为我没有正确解释自己。

我希望能够存储在公共位置此代码以访问JSON中的值:

->{'path1'}->{'path2'}->{'x'}

将来可能会更改为:

->{'path1_1'}->{'path2_1'}->{'path3_1'}->{'x_1'}

pd:如果使用@Stevieb的答案提供的代码,我将无法保存所需的结构。添加这两行:

print Dumper($href) . "n";
print to_json($href) . "n";

屈服于:

$VAR1 = {
          'PATH1' => {
                       'PATH2' => {
                                    'a' => 'aaa',
                                    'b' => 'bbb',
                                    'y' => 'yyy',
                                    'z' => 'zzz'
                                  }
                     }
        };
{"PATH1":{"PATH2":{"a":"aaa","b":"bbb","y":"yyy","z":"zzz"}}}

所以总结一下。我希望能够存储一个复杂结构的哈希路径,并具有许多未固定的键。

ikegami,在注释中指定自动生成您的潜艇。这是一个例子,它为您提供了一个单个改变路径的地方,并且在操作方面相当平稳。我还将您的集合/获取方法减少到了同时执行两项操作的单个组合sub:

use warnings;
use strict;
use constant {
    PATH1 => '/home/steveb/PATH1',
    PATH2 => '/home/steveb/PATH2',
};
BEGIN {
    for my $elem (qw(a b y z)){
        my $sub_name = "element_$elem";
        no strict 'refs';
        *$sub_name = sub {
            my ($hash_ref, $value) = @_;
            $hash_ref->{PATH1}{PATH2}{$elem} = $value if defined $value;
            return $hash_ref->{PATH1}{PATH2}{$elem};
        }
    }
}
my $href = {};
element_a($href, 'aaa');
element_b($href, 'bbb');
element_y($href, 'yyy');
element_z($href, 'zzz');
print element_a($href) . "n";
print element_b($href) . "n";
print element_y($href) . "n";
print element_z($href) . "n";

输出:

aaa
bbb
yyy
zzz

做什么,将两个常数值(PATH1PATH2(设置为您想要的值。这发生在编译时。接下来,在BEGIN块中,我们基于文本字符串(" element_"(动态创建子例程,并在该名称的末尾附加元素。然后,我们将其分配为具有匿名子例程的符号表中的typeglob,并具有所需的功能。这也发生在编译时。for my $elem...行中的每个条目都将创建element_X() sub。

如果您的路径发生了变化,则只需在use constant块中更改它。

现在,您似乎正在使用一个对象,那么为什么不只是将数据倒在其中,而不是通过任意的hashref传递呢?这是一个例子。请注意,我是use 5.10.0; -ing,以便我可以使用//=定义或操作员(以及say功能(:

软件包:

package Blah;
use warnings;
use strict;
use 5.10.0;
use constant {
    PATH1 => '/home/steveb/path1',
    PATH2 => '/home/steveb/path2',
};
BEGIN {
    for my $elem (qw(a b y z)){
        my $sub_name = "element_$elem";
        no strict 'refs';
        *$sub_name = sub {
            my ($self, $value) = @_;
            return $self->{PATH1}{PATH2}{$elem} //= $value;
        }
    }
}
sub new {return bless {}, shift};
1;

脚本示例:

use warnings;
use strict;
use 5.10.0;
use Blah;
my $blah = Blah->new;
$blah->element_a('a');
$blah->element_b('b');
$blah->element_y('y');
$blah->element_z('z');
say $blah->element_a;
say $blah->element_b;
say $blah->element_y;
say $blah->element_z;

输出:

a
b
y
z

注意:如果不进行极端谨慎,直接使用符号表可能很危险。覆盖您并非故意的事情是微不足道的,这可能会导致各种小小的或大的悲伤。这就是为什么正在使用no strict 'refs'的原因。我将其瞄准了可能的最小块,并且(隐式(确保没有其他element_* Symtab(符号表(条目存在。strict会捕获这样的违规行为,这就是为什么我们始终推荐它,并且仅将其禁用尽可能小的范围,只有"违反规则"所需的零件,并且只有绝对必需的禁用范围。

如果您的路径具有fix depth =>您可以将其用作数组(或数组参考(并使用此结构,例如:

sub get_element_x {
  my ($hash_ref, $path) = @_;
  return $hash_ref->{$path->[0]}->{$path->[1]}->{$path->[2]};
}

最新更新