可以在更深层次的绑定哈希分配上调用 STORE 吗?
Possible to call STORE on deeper level tied hash assignment?
我正在尝试为具有以下属性的“持久 YAML 哈希”编写 Perl 模块:
- 每次访问时,检查 YAML 文件是否已更改,如果已更改,则重新加载。
- 一旦哈希中的任何数据发生变化,立即保存。
- 不要保存在
UNTIE
,这样当您只读取值时文件不会更新。
我的第一次尝试似乎很有效:
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}
被分配时不会被调用。
有什么方法可以让它做我想做的事吗?
您还需要绑定 %{ $foo{a} }
、%{ $foo{a}{b} }
和 %{ $foo{a}{b}{c} }
。
您可以递归地将散列和数组绑定到 TIEHASH
中的数据结构中。不要忘记对通过 STORE
!
添加到结构中的数据做同样的事情
您可能希望对数据结构的根和 non-root 个节点使用不同的 class。
警告:使用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});
- ...
我正在尝试为具有以下属性的“持久 YAML 哈希”编写 Perl 模块:
- 每次访问时,检查 YAML 文件是否已更改,如果已更改,则重新加载。
- 一旦哈希中的任何数据发生变化,立即保存。
- 不要保存在
UNTIE
,这样当您只读取值时文件不会更新。
我的第一次尝试似乎很有效:
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}
被分配时不会被调用。
有什么方法可以让它做我想做的事吗?
您还需要绑定 %{ $foo{a} }
、%{ $foo{a}{b} }
和 %{ $foo{a}{b}{c} }
。
您可以递归地将散列和数组绑定到 TIEHASH
中的数据结构中。不要忘记对通过 STORE
!
您可能希望对数据结构的根和 non-root 个节点使用不同的 class。
警告:使用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});
- ...