我需要将数据结构从数组列表转换为树状结构。在开始处理数据之前,我知道树的深度,但我想保持灵活性,以便我可以重用代码。
所以我想到了动态生成子引用(从基于 Moose 的模块中)从数组到树的想法。像这样(以简化的方式):
use Data::Dump qw/dump/;
sub create_tree_builder {
my $depth = shift;
return eval join '', 'sub { $_[0]->{$_[',
join(']}->{$_[', (1..$depth)),
']} = $_[', $depth + 1 , '] }';
}
my $s = create_tree_builder(5);
my $tree = {};
$s->($tree, qw/one two three four five/, 'a value');
print dump $tree;
# prints
# {
# one => { two => { three => { four => { five => "a value" } } } },
# }
这为我打开了世界,我发现这个 eval-in 过程很酷的用途——将参数化生成的字符串放入一个函数中(显然,这是一个寻找问题的解决方案)。
然而,感觉有点好得令人难以置信,几乎。
对这种做法有什么建议吗?或者改进建议?
我可以清楚地看到,评估任意输入可能不是最安全的事情,但还有什么呢?
跟进
感谢所有的答案。我使用了 amon 的代码并进行了一些基准测试,如下所示:
use Benchmark qw(:all) ;
$\ = "\n";
sub create_tree_builder {
my $depth = shift;
return eval join '', 'sub { $_[0]->{$_[',
join(']}->{$_[', (1..$depth)),
']} = $_[', $depth + 1 , '] }';
}
my $s = create_tree_builder(5);
$t = sub {
$_[0] //= {};
my ($tree, @keys) = @_;
my $value = pop @keys;
$tree = $tree->{shift @keys} //= {} while @keys > 1;
$tree->{$keys[0]} = $value;
};
cmpthese(900000, {
'eval' => sub { $s->($tree, qw/one two three four five/, 'a value') },
'build' => sub { $t->($tree, qw/one two three four five/, 'a value') },
});
结果显然有利于构建树,而不是评估工厂:
Rate build eval
build 326087/s -- -79%
eval 1525424/s 368% --
我承认我以前可以这样做。我将尝试使用更多随机树(而不是一遍又一遍地分配相同的元素),但我认为结果应该不同。
非常感谢您的帮助。