Все дело в Scalar
, который не был деконтейнеризирован.
Вы можете изменить return $d
на return @$d
Одним из способов добиться такого же поведения является изменение процедуры b
.
Вы написали: "Обе эти подпрограммы возвращают массив, но возвращаемые массивы ведут себя по-разному". Но, как отмечает Холли, b
вместо этого возвращает Scalar
, привязанный к $d
(который, в свою очередь, содержит массив):
sub b { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().VAR.WHAT; # (Scalar)
Вы можете изменить это, "деконтейнеризируя" $d
, например, добавив перед @
:
sub b { my $d = [ 1, 2, 3, 4 ]; return @$d };
say b().VAR.WHAT; # (Array)
my @f = b();
say @f; # [1 2 3 4]
say @f[1]; # 2
Или измените @f = b()
на @f = b[]
Если вы не деконтейнеризировали значение, возвращаемое b
, тогда возникает вторая проблема/возможность.
Независимо от того, что возвращает b
, присваивание @f
будет оценивать список присваиваемых ему значений. В контексте списка Scalar
остаются как есть (так же, как они были с простым return $d
). Поэтому, если вы не измените b
на деконтейнеризацию, тогда вам нужно будет сделать это в назначении на @f
вместо этого, если вы хотите, чтобы @e
и @f
в конечном итоге были одинаковыми. .
На этот раз вы не можете просто добавить @
для этого. Потому что это будет означать @b
, что Раку интерпретирует как @b
переменную.
Одним из вариантов является запись @f = @(b())
, но это будет некрасиво/неидиоматично. Другой вариант — написать @f = b[]
. Это использует тот факт, что круглые скобки в вызовах b
были избыточными. Добавление []
("срез дзен") имеет тот же эффект, что и запись @(b)
, но на один символ меньше.
Итак, для деконтейнеризации в назначении списка можно написать:
sub b { my $d = [ 1, 2, 3, 4 ]; return $d };
say b().VAR.WHAT; # (Scalar)
my @f = b[];
say @f; # [1 2 3 4]
say @f[1]; # 2
"разъяснить в документации"
Каким выражением правильно указать в документации какой тип массива что возвращает подпрограмма?
Я не уверен, что вы имеете в виду под этим вопросом, даже с переключением на просто "что возвращается".
Я также не уверен, на что указать вам в документе, и даже если есть что-то хорошее, на что можно указать, относительно сценария в вашем SO.
Я знаю, что на моем месте следующие разделы документа смущают относительно вашего сценария:
-
Ссылка на раздел Скалярные контейнеры и списки вещей Holli. Этот раздел, как мне кажется, в настоящее время посвящен использованию контейнеров Scalar
внутри списков/массивов, что имеет отношение к второй проблеме , о которой я писал выше ($d
находится в списке справа от присвоение @f
). Но это не относится к первой проблеме, о которой я писал (return $d
из подпрограммы b
). Там все наоборот, а именно внутри Scalar
находится массив.
-
Раздел Скалярные контейнеры выше на той же странице. Начальное предложение — «Хотя объекты типа Scalar
повсюду в Раку, вы редко видите их непосредственно как объекты, потому что большинство операций по деконтейнеризации ...» работает для меня. Но «подпрограмма может вернуть контейнер, если он помечен как is rw
» более проблематичен. Это является истинным:
my $x = 23;
sub f() is rw { $x };
f() = 42;
say $x; # OUTPUT: «42»
Но не нужно пометить подпрограмму is rw
для возврата контейнера. Можно использовать подпрограмму return
, как вы сделали:
my $x = 23;
sub f() { return $x };
say f().VAR.WHAT; # OUTPUT: «Scalar»
Они ведут себя по-разному, потому что вы возвращаете разные вещи. Один представляет собой массив — список вещей, а второй возвращает скаляр — одну вещь, которая содержит массив. См. docs.raku.org/language/…
@Holli: я знаю, что возвращаю разные вещи, которые ведут себя по-разному.