首页 > 解决方案 > 可以在更深层次的绑定哈希分配上调用 STORE 吗?

问题描述

我正在尝试为“持久 YAML 哈希”编写一个 Perl 模块,具有以下属性:

我的第一次尝试似乎效果很好:

package YAMLHash;

use v5.24;
use warnings;
use experimental 'signatures';

use YAML::XS qw(DumpFile LoadFile);
use File::stat;

sub refresh($self)
{
    if (-f $self->{file}) {
        if (stat($self->{file})->mtime > $self->{mtime}) {
            $self->{data} = LoadFile($self->{file});
            $self->{mtime} = stat($self->{file})->mtime;
        }
    }
}

sub save($self)
{
    DumpFile($self->{file}, $self->{data});
    $self->{mtime} = stat($self->{file})->mtime;
}

sub TIEHASH($class, @args)
{
    my ($filename) = $args[0];
    die "No filename specified" unless $filename;
    my $self = bless { data=>{}, file=>$filename, mtime=>0 }, $class;
    refresh($self);
    return $self;
}

sub FETCH($self, $key = '')
{
    refresh($self);
    return $self->{data}{$key};
}

sub EXISTS($self, $key)
{
    refresh($self);
    return exists($self->{data}{$key});
}

sub FIRSTKEY($self)
{
    refresh($self);
    my @ignore = keys %{$self->{data}}; # reset iterator
    return each %{$self->{data}};
}

sub NEXTKEY($self, $lastkey)
{
    refresh($self);
    return each %{$self->{data}};
}

sub SCALAR($self)
{
    return scalar %{$self->{data}};
}

sub STORE($self, $key, $value)
{
    refresh($self);
    $self->{data}{$key} = $value;
    save($self);
}

sub DELETE($self, $key)
{
    refresh($self);
    delete $self->{data}{$key};
    save($self);
}

sub CLEAR($self, $key)
{
    $self->{data} = {};
    save($self);
}

1;

我尝试如下:

use YAMLHash;

tie my %foo, 'YAMLHash', 'test.yaml';

$foo{hello} = 'world';
$foo{answer} = 42;
$foo{counter}++;

生成的 YAML 文件如下所示:

---
answer: 42
counter: 1
hello: world

但后来我将示例代码更改为:

use YAMLHash;

tie my %foo, 'YAMLHash', 'test.yaml';

$foo{hello} = 'world';
$foo{answer} = 42;
$foo{counter}++;
$foo{a}{b}{c}{d} = 'e';

结果是:

---
a: {}
answer: 42
counter: 2
hello: world

因此,显然,在创建STORE时调用$foo{a},而不是在$foo{a}{b}{c}{d}分配时调用。

有什么办法可以让它做我想要的吗?

标签: perltie

解决方案


您将需要 tie %{ $foo{a} }%{ $foo{a}{b} }以及%{ $foo{a}{b}{c} }

您可以递归地将数据结构中的哈希和数组绑定到TIEHASH. 不要忘记对通过添加到结构中的数据执行相同的操作STORE

您可能希望对数据结构的根节点和非根节点使用不同的类。

警告:使用tie会使访问变慢。


请注意,您也需要绑定标量,而不仅仅是哈希(和数组)。以下所有内容都会在不调用的情况下更改哈希元素的值STORE

  • 直接更改标量:
    • ++$foo{a};
    • chomp($foo{a});
    • $foo{a} =~ s/x/y/g;
    • ...
  • 通过别名或引用更改标量:
    • my \$x = \$foo{a}; $x = 123;
    • my $r = \$foo{a}; $$r = 123;
    • for ($foo{a}) { $_ = 123; }
    • sub { $_[0] = 123; }->($foo{a});
    • ...

推荐阅读