Мне трудно понять, когда и почему значение, сохраняемое помещаемым Scalar
контейнером, изменяется после отправки. Я попытаюсь проиллюстрировать проблему, с которой я столкнулся, в более сложном контексте на двух стилизованных примерах.
* Пример 1 * В первом примере скаляр $i
помещается в массив @b
как часть a List
. После отправки значение, хранящееся в скаляре, явно обновляется в последующих итерациях цикла for с использованием $i++
инструкции. Эти обновления влияют на значение в массиве @b
: в конце цикла for @b[0;0]
равно 3
и больше не равно 2
.
my @b;
my $i=0;
for 1..3 -> $x {
$i++;
say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
if $x == 2 {
@b.push(($i,1));
say 'Pushed $i : ', @b[0;0].VAR.WHICH, " ", @b[0;0].VAR.WHERE;
}
}
say "Post for-loop";
say "Array : ", @b;
say 'Pushed $i : ', @b[0;0].VAR.WHICH, " ", @b[0;0].VAR.WHERE;
Выходной пример 1:
Loose var $i: Scalar|94884317665520 139900170768608
Loose var $i: Scalar|94884317665520 139900170768648
Pushed $i : Scalar|94884317665520 139900170768648
Loose var $i: Scalar|94884317665520 139900170768688
Post for-loop
Array : [(3 1)]
Pushed $i : Scalar|94884317665520 139900170768688
* Пример 2 * Во втором примере скаляр $i
является переменной цикла. Несмотря на то, $i
обновляется после того , как была нажата (теперь неявно , а не в явном виде), значение $i
в массиве @c
никак не
изменится после толчка; то есть после цикла for это все еще 2
не 3
.
my @c;
for 1..3 -> $i {
say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
if $i == 2 {
@c.push(($i,1));
say 'Pushed $i : ', @c[0;0].VAR.WHICH, " ", @c[0;0].VAR.WHERE;
}
}
say "Post for-loop";
say "Array : ", @c;
say 'Pushed $i : ', @c[0;0].VAR.WHICH, " ", @c[0;0].VAR.WHERE;;
Выходной пример 2:
Loose var $i: Scalar|94289037186864 139683885277408
Loose var $i: Scalar|94289037186864 139683885277448
Pushed $i : Scalar|94289037186864 139683885277448
Loose var $i: Scalar|94289037186864 139683885277488
Post for-loop
Array : [(2 1)]
Pushed $i : Scalar|94289037186864 139683885277448
Вопрос: Почему $i
в @b
в примере 1 , обновленный после толчка, в то время как $i
в @c
в примере 2 не является?
edit : После комментария @ timotimo я включил вывод .WHERE
в примерах. Это показывает (WHICH / логическое) скалярное тождество $i
остается тем же самым, в то время как его адрес памяти изменяется через различные итерации цикла. Но это не объясняет, почему в примере 2 выдвинутый скаляр остается привязанным к той же WHICH-идентичности в сочетании со старым адресом («448»).
источник
.WHERE
вместо,.WHICH
вы можете видеть, что скаляр на самом деле каждый раз повторяет цикл. Это происходит потому, что заостренные блоки «вызываются», а подпись «привязывается» к каждому вызову.Ответы:
Скалярное значение - это просто контейнер. Вы можете думать о них как об умном указателе, а не как о примитивном значении.
Если вы делаете назначение
Вы меняете значение скаляров, контейнер остается прежним.
Рассматривать
а также
Оба из которых работают, как ожидалось. Но: в обоих случаях вещь в списке больше не является изменчивой, потому что нет контейнера.
поэтому умрет. Так что просто используйте переменную цикла, верно?
Нет.
даже если мы перебираем список изменчивых вещей.
Таким образом, здесь нет псевдонимов, вместо этого переменная цикла всегда является одним и тем же контейнером и получает назначенные значения, которые поступают из других контейнеров.
Мы можем сделать это все же.
Способ сделать изменяемую вещь - это использовать промежуточную переменную.
работает отлично. Или короче и больше в оригинальном контексте
Смотрите также:
https://perl6advent.wordpress.com/2017/12/02/#theoneandonly https://docs.perl6.org/language/containers
источник
($x,1)
, вы можете также сделать[$x,1]
который бы создать новый контейнер (также1
, кстати)Int
объект ->Int
заменяется в цикле for -> контейнер указывает на новыйInt
), но второй - нет.Поработав и подумав над моим вышеупомянутым вопросом в течение некоторого времени, я поставлю на вопрос ... Это чистая догадка с моей стороны, поэтому, пожалуйста, не стесняйтесь говорить, что это бессмысленно, и если вы знаете, Почему...
В первом примере
$i
определяется за пределами лексической области цикла for. Следовательно,$i
существует независимо от цикла и его итераций. Когда на$i
него ссылаются из цикла, есть только один,$i
который может быть затронут. Это то,$i
что вставляется в него@b
, и его содержимое впоследствии изменяется в цикле.Во втором примере
$i
определяется внутри лексической области действия цикла for. Как указал @timotimo, указанный блок get вызывается для каждой итерации, как подпрограмма;$i
поэтому вновь объявляется для каждой итерации и попадает в соответствующий блок. Когда на$i
него ссылаются внутри цикла, ссылка на специфичную для итерации блока$i
, которая обычно перестает существовать, когда заканчивается соответствующая итерация цикла. Но поскольку в какой-то момент$i
происходит принудительное переключение, сборщик мусора не может удалить@c
ссылку на специфическое для итерации$i
значение2
после завершения итерации. Он останется в существовании ..., но все равно будет отличаться от$i
последующих итераций.источник