将预编译的正则表达式放在列表中引用的两个不同的哈希值中:
my @list = ();
my $regex = qr/ABC/;
push @list, { 'one' => $regex };
push @list, { 'two' => $regex };
use Data::Dumper;
print Dumper(\@list);
我希望:
$VAR1 = [
{
'one' => qr/(?-xism:ABC)/
},
{
'two' => qr/(?-xism:ABC)/
}
];
但我们得到一个循环引用:
$VAR1 = [
{
'one' => qr/(?-xism:ABC)/
},
{
'two' => $VAR1->[0]{'one'}
}
];
无限期嵌套的哈希引用和浅层复制$regex
会发生这种情况。
我假设基本原因是预编译的正则表达式实际上是引用,并且同一列表结构中的引用被压缩为优化(\ $标量的行为方式相同)。我没有完全看到这样做的效用(可能是对引用的引用具有相同的内存占用),但也许基于内部表示的原因
这是正确的行为吗?我可以阻止它发生吗?除了可能使GC更加困难之外,这些圆形结构会产生非常严重的问题。例如,迭代可能包含相同正则表达式的查询列表会使MongoDB驱动程序崩溃,并使用令人讨厌的段错误(请参阅https://rt.cpan.org/Public/Bug/Display.html?id=58500)
答案 0 :(得分:9)
这是预期的行为。
您的引用并非真正的通告;你有两个单独的项目,指向同一件事。 Data :: Dumper在内存中打印人类可读的Perl可解析的数据结构表示,它的真正含义是$list[0]->{one}
和$list[1]->{two}
都指向同一个东西。
Perl使用引用计数垃圾收集,虽然它可能会遇到循环数据结构的问题,但这种数据结构没有特别的问题。
答案 1 :(得分:6)
这里没有什么好笑的事。
$list[0]{one}
相同的引用。 $list[0]{two}
。答案 2 :(得分:1)
我假设基本原因是这样的 实际上是预编译的正则表达式 引用和内部的引用 相同的列表结构被压缩为 优化(\ $标量表现为 同样的方式)。我没有完全看到 这样做的效用(大概是一个 对引用的引用也是一样的 内存足迹),但也许有一个 基于内部的原因 表示
原因是它可能是对嵌套在某处的数据结构的引用,其中包含一个返回顶层(循环)的引用。如果它继续进入这样的结构,那么它将创建一个无限循环。它避免这种情况的方法是永远不会递归到它已经看过的参考文献中,所以它会打印它已经看过它并引导你到之前的打印位置。
在这种情况下,没有循环,但是Data :: Dumper无法知道在它进入结构之前就已经太晚了。
对于这样的标量,这可能不是必要的,但可能会发生,因为Data :: Dumper会在检查类型之前检查它是否已经看过引用。它还提供了一个好处,它表明它是对相同数据的引用,而不是它的副本,这可能是有用的信息,如果它只打印了值就会丢失。