Ответ 1
Вы нашли захватывающий фрейм.
Когда вы явно устанавливаете элемент, он сначала возникает. Если массив расширен так, что несколько индексов попадают в диапазон этого массива, никакие скаляры неявно инициализируются на этих позициях. Пример:
my @array;
$array[2] = undef; # this extends the array
# now elements 0–2 report as `undef`, but only #2 was initalized
Когда мы спрашиваем, существуют ли эти элементы, мы получаем:
say "index $_ ", exists $array[$_] ? "exists" : "doesn't exist" for 0 .. 4;
Вывод:
index 0 doesn't exist
index 1 doesn't exist
index 2 exists
index 3 doesn't exist
index 4 doesn't exist
Эта оптимизация избавляет вас от выделения неиспользуемых скаляров на этих позициях; код доступа к массиву просто возвращает undef
, если в противном случае ничего не говорится.
Теперь это квадраты плохо с вызовами функций. Когда вызывается подпрограмма, в стек помещается плоский список скаляров, который затем доступен как @_
. Здесь нет копирования, так что это вызов псевдонимом. Теперь, когда элемент $_[0]
обращается к вашему югу, здесь нет скаляра, поэтому он создает новый в @_
:
sub crazy {
say 1*exists $_[0];
$_[0] = 1;
say 1*exists $_[0];
}
my @array; $array[2] = 0;
crazy @array;
say 1*exists $array[0];
Вывод:
0
1
0
Внутренне скаляр является указателем на структуру SV
. Эти указатели копируются в стек, поэтому это делает невозможным фактическое изменение оригинала @array
.