perl - 可以在更深层次的绑定哈希分配上调用 STORE 吗?
问题描述
我正在尝试为“持久 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}
分配时调用。
有什么办法可以让它做我想要的吗?
解决方案
您将需要 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});
- ...
推荐阅读
- sql - 如何在存储过程中循环选择语句返回的每一行
- c++ - ASCII 字符串组合
- c - 在C中通过引用传递指针
- edi - EDI 标头 - 为什么 ISA12 和 GS8 都有版本号?
- r - 上传文件后如何在闪亮的应用程序中绘制图形
- kotlin - 如何在 Kotlin DSL 中设置 Rx Action Consumer
- python - 如何在熊猫数据框中创建一个布尔空列?
- java - DataFlow (Apache Beam) 中 Pub/Sub 的自定义时间戳和窗口化
- c++ - 有没有办法在 C/C++ 中撤消 SQLite3 步骤调用?
- javascript - 根据名称从条目计数中获取一行中的值