【问题标题】:How can I store hash paths to reuse them in perl?如何存储哈希路径以在 perl 中重用它们?
【发布时间】:2019-08-09 04:54:39
【问题描述】:

假设我有大量元素嵌套在哈希中(来自 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"}}}

总结一下。我希望能够存储具有多个不固定键的复杂结构的哈希路径。

【问题讨论】:

  • 您可以使用配置文件来定义您的“路径”。在您的 getter/setter/其他相关功能中,您可以只参考 config-file-keys。因此,每当您的 JSON 键发生变化时,您只需在配置文件中进行更改,而不是在所有函数中进行更改。
  • 有很多方法(例如this),但是由于必须更改两个位置而不是一个位置,因此是否值得节省额外的运行时费用?
  • 您可以通过生成 getter 和 setter 来避免额外的运行时开销。
  • 您需要与组织内的某个人讨论如何标准化 API。一次性转换这样的东西很容易,但如果它总是一个猜谜游戏,恕我直言,这项工作不值得。

标签: perl hash path store


【解决方案1】:

ikegami,在 cmets 中指定了自动生成您的潜艇。这是一个示例,它为您提供了一个更改路径的单一位置,并且在其操作中相当方便。我还将你的 set/get 方法简化为一个组合的 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_”)动态创建子例程,并在该名称的末尾附加一个元素。然后,我们将其分配为 symbol table 中的 typeglob,并带有一个具有我们想要的功能的匿名子例程。这也发生在编译时。 for my $elem... 行中的每个条目都会创建一个 element_X() 子。

如果您的路径发生变化,您只需在 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 捕捉到这样的可能违规行为,这就是为什么我们始终推荐它,并且只在尽可能小的范围内禁用它,只有“打破规则”所需的部分,并且只有在禁用它时绝对需要。

【讨论】:

  • 我刚刚更新了这个问题,因为我认为我没有正确解释我想要做什么。感谢您花时间写下答案,这有助于我肯定地了解更多信息,但我认为它并不能回答我想问的问题。谢谢。
猜你喜欢
  • 1970-01-01
  • 2019-03-23
  • 2010-09-16
  • 2010-09-20
  • 2015-10-06
  • 2016-06-16
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多