Помещение предварительно скомпилированного regex в двух различных хешах сослалось в списке:
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
.
Я предполагаю, что основная причина состоит в том, что предварительно скомпилированные regexes являются на самом деле ссылками, и ссылки в той же структуре списка уплотнены как оптимизация (\, $scalar ведет себя тот же путь). Я не полностью вижу утилиту выполнения этого (по-видимому, ссылка на ссылку имеет тот же объем потребляемой памяти), но возможно существует причина на основе внутреннего представления
Действительно ли это - корректное поведение? Я могу мешать ему произойти? Кроме вероятного создания более трудного GC, эти круговые структуры создают довольно серьезные головные боли. Например, итерация по списку запросов, которые могут иногда содержать то же регулярное выражение, разрушит драйвер MongoDB с противным segfault (см. https://rt.cpan.org/Public/Bug/Display.html? id=58500)
Это ожидаемое поведение.
Ваша ссылка не совсем круговая; у вас есть два отдельных элемента, которые указывают на одну и ту же вещь. Data::Dumper печатает человекочитаемое, разбираемое Perl представление ваших структур данных в памяти, и на самом деле это означает, что $list[0]->{one}
и $list[1]->{two}
указывают на одно и то же.
Perl использует сборку мусора с подсчетом ссылок, и хотя у него могут возникнуть проблемы с кольцевыми структурами данных, эта структура данных не представляет особой проблемы.
Ничего смешного здесь не происходит.
$ list [0] { one}
, как и в $ list [0] {two}
.