Динамические переменные, CALLERS, скаляры и присваивание

Недавно я заметил, что повторная инициализация динамических переменных не имеет семантики, которую я ожидал в большинстве случаев с использованием присваивания (однако привязка работает так, как я ожидал).

В частности, в этом коде:

sub g {
    my $*i  = CALLERS::<$*i>  // 0;
    my $*a1 = CALLERS::<$*a1> // Array.new;
    my @*a2 = CALLERS::<@*a2> // Array.new;
    $*i++;
    $*a1.push: 'v1';
    @*a2.push: 'v2';
    dd $*i;
    dd $*a1;
    dd @*a2;
}
sub f {
    my $*i = 0;
    my $*a1 = Array.new;
    my @*a2 = Array.new;
    g; g; g;
}
f

Я ожидал вывода 3, ["v1", "v1", "v1"] и ["v2", "v2", "v2"], но вместо этого получил 1, $["v1", "v1", "v1"], ["v2"]. Переключение на привязку решает проблему, так что я не пытаюсь решить проблему, но мне бы очень хотелось понять, почему присваивание здесь не работает. Я заметил, что Scalar, указывающий на Array, работает, а Scalar, указывающий на Int, — нет. Но в любом случае я бы подумал, что вновь назначенная переменная получит значение от CALLERS. Что мне не хватает в семантике присваивания?


person codesections    schedule 04.06.2021    source источник


Ответы (1)


Что мне не хватает в семантике присваивания?

Я думаю, что то, что вам не хватает, не имеет ничего общего с динамическими переменными как таковыми. Я думаю, что вам не хватает того факта, что:

my @a = Array.new;

в основном noop. Из-за правила единственного аргумента это то же самое, что:

my @a = ();

что то же самое, что:

my @a;

Итак, в вашем примере в sub f:

my @*a2 = Array.new;

in просто создает пустой массив в динамической переменной.

Затем в sub g:

my @*a2 = CALLERS::<@*a2> // Array.new;

просто делает (из-за правила единственного аргумента):

my @*a2;

и, следовательно, вы не видите pushes, которые вы делали раньше, потому что каждый вызов начинается заново.

Что касается значения $*i в sub g: это также просто увеличивает копию вызывающих объектов $*i, поэтому значение остается равным 1 при каждом вызове.

Причина, по которой $*a1 работает, заключается в том, что контейнеризация останавливает выравнивание правила с одним аргументом. Обратите внимание на разницу между:

sub a(+@a) { dd @a }; a [2,3,4];  # [2,3,4]

а также:

sub a(+@a) { dd @a }; a $[2,3,4];  # [[2,3,4],]
person Elizabeth Mattijsen    schedule 04.06.2021