这里发生了什么?
如果%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
最佳答案
此处观察到的差异与以下内容相同:
my $a = [1,2,3];
.say for $a; # [1 2 3]
.say for $a.Array; # 1\n2\n3\n
$
标记可以认为是“单个项目”。因此,当给for
时,它将看到并说“aha,一个项目”并运行一次循环。此行为在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
绑定(bind)到调用该方法的对象,并从其容器中删除该对象。但是,可以编写method bar(\raw-self:) { }
来完全按照提供的方式恢复它。关于raku - 在Perl 6中使用数组值散列,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50299548/