Хеш со значениями Array в Perl 6 - PullRequest
0 голосов
/ 11 мая 2018

Что здесь происходит?

Почему %a{3} и %a{3}.Array отличаются, если %a имеет Array значения, а %a{3} является Array?

> my Array %a
{}
> %a{3}.push("foo")
[foo]
> %a{3}.push("bar")
[foo bar]
> %a{3}.push("baz")
[foo bar baz]
> .say for %a{3}
[foo bar baz]
> %a{3}.WHAT
(Array)
> .say for %a{3}.Array
foo
bar
baz

Ответы [ 2 ]

0 голосов
/ 12 мая 2018

Наблюдаемая здесь разница такая же, как и с:

my $a = [1,2,3];
.say for $a;        # [1 2 3]
.say for $a.Array;  # 1\n2\n3\n

Сигилу $ можно рассматривать как означающую "один предмет".Таким образом, если ему присвоить for, он увидит это и скажет «ага, один элемент» и запустит цикл один раз.Это поведение одинаково для for и операторов и подпрограмм .Например, вот приведенные оператором zip массивы и их детализированные массивы:

say [1, 2, 3] Z [4, 5, 6];    # ((1 4) (2 5) (3 6))
say $[1, 2, 3] Z $[4, 5, 6];  # (([1 2 3] [4 5 6]))

Напротив, вызовы методов и операции индексации всегда будут вызываться для того, что находится внутри Scalarконтейнер.Вызов .Array на самом деле не работает, поскольку он уже вызывается на Array, и его интересная работа фактически заключается в действии самого вызова метода, который разворачивает контейнер Scalar..WHAT подобен вызову метода и рассказывает о том, что находится внутри любого контейнера Scalar.

Значения массива и хеша - по умолчанию - Scalar контейнеры, которые, в свою очередь,держать значение.Тем не менее, .WHAT, используемый для просмотра значения, скрывал это, поскольку речь идет о том, что находится внутри Scalar.В отличие от этого, .perl [1] дает понять, что есть один элемент:

my Array %a;
%a{3}.push("foo");
%a{3}.push("bar");
say %a{3}.perl;      $["foo", "bar"]

Существуют различные способы удаления элементов:

%a{3}.Array     # Identity minus the container
%a{3}.list      # Also identity minus the container for Array
@(%a{3})        # Short for %a{3}.cache, which is same as .list for Array
%a{3}<>         # The most explicit solution, using the de-itemize op
|%a{3}          # Short for `%a{3}.Slip`; actually makes a Slip

Я бы, вероятно, использовалfor %a{3}<> { } в этом случае;и он короче, чем вызовы метода, и дает понять, что мы делаем это исключительно для того, чтобы удалить элементизацию, а не принуждение.

Хотя for |%a{3} { } также отлично работает и визуально хорош, это единственный, которыйне оптимизируется до простого удаления чего-либо из его контейнера Scalar, а вместо этого создает промежуточный объект Slip, который может немного замедлить итерацию (хотя в зависимости от того, сколько работы выполняется циклом,это вполне может быть шумом).


[1] Исходя из того, что я написал, можно задаться вопросом, почему .perl может восстановить тот факт, что что-то было перечислено.Вызов метода $foo.bar действительно делает что-то вроде $foo<>.^find_method('bar')($foo).Затем, в method bar() { self }, self привязывается к объекту, на котором был вызван метод, удаляется из его контейнера.Тем не менее, можно написать method bar(\raw-self:) { }, чтобы восстановить его точно так, как он был предоставлен.

0 голосов
/ 11 мая 2018

Проблема заключается в том, что Scalar контейнеры выполняют перенаправление DWIM.

%a{3} привязано к контейнеру Scalar.

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

В отличие от этого, когда вы ссылаетесь на Array контейнер как одинсущность, вы действительно получаете доступ к этому Array контейнеру, без ловкости рук.

Чтобы увидеть, с чем вы действительно имеете дело, используйте .VAR, который показывает, что переменная (илиэлемент составной переменной), а не позволяет любому контейнеру, с которым он связан, притворяться, что его там нет.

say %a{3}.VAR ;       # $["foo", "bar", "baz"]
say %a{3}.Array.VAR ; # [foo bar baz]

Это поспешное объяснение.На самом деле я работаю над постом, специально посвященным контейнерам.

...