В Perl, благодаря "самооживлению" ссылок, очень удобна работа с многоуровневыми структурами данных. Например:
При этом удобство работы с многоуровневыми структурами данных снижается.
Необходимо извлечь значение, распаковать его, а если значения не было, то создать. Затем после изменения - запаковать и поместить обратно.
Проще написать функцию для внесения изменений, которая будет вызываться примерно вот как:
my %foo = (); my $k = "k"; $foo{$k}{a} = "b"; $foo{$k}{c} = "d";Однако, если %foo - это внешняя база данных, например BerkeleyDB, то значения необходимо запаковать тем же Storable или JSON.
При этом удобство работы с многоуровневыми структурами данных снижается.
Необходимо извлечь значение, распаковать его, а если значения не было, то создать. Затем после изменения - запаковать и поместить обратно.
my %foo = (); my $k = "k"; my $f; if (my $_f = $foo{$k}) { $f = decode_json $_f; } else { $f = {}; } $$f{a} = "b"; $$f{c} = "d"; $foo{$k} = encode_json $f;Теперь представим, что это необходимо делать в разных местах программы.
Проще написать функцию для внесения изменений, которая будет вызываться примерно вот как:
$foo->($k, sub { my ($v) = @_; $$v{a} = "b"; $$v{c} = "d"; return $v; } );Немножко многословно. Но в Perl есть "магическая" переменная $_, которая позволяет сделать следующие:
$foo->($k, sub { $$_{a} = "b"; $$_{c} = "d"; } );Соответственно, сама функция будет выглядеть так:
my %foo = (); my $foo = sub { my ($k, $sub) = @_; local $_; if (my $_f = $foo{$k}) { $_ = decode_json $_f; } else { $_ = {}; } $sub->(); $foo{$k} = encode_json $_; };Хотя можно и так:
sub foo(&$); my %foo = (); local *foo = sub { my ($sub, $k) = @_; local $_; if (my $_f = $foo{$k}) { $_ = decode_json $_f; } else { $_ = {}; } $sub->(); $foo{$k} = encode_json $_; }; foo { $$_{a} = "b"; $$_{c} = "d"; } "k";Даже не знаю как лучше... :-)