В 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";
Даже не знаю как лучше... :-)