在Perl 6中使用Array值进行哈希处理

Eug*_*sky 5 perl6

这里发生了什么?

为什么%a{3}%a{3}.Array不同的,如果%aArray值,并且%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
Run Code Online (Sandbox Code Playgroud)

Jon*_*ton 12

这里观察到的差异与以下相同:

my $a = [1,2,3];
.say for $a;        # [1 2 3]
.say for $a.Array;  # 1\n2\n3\n
Run Code Online (Sandbox Code Playgroud)

$印记可以被认为是"单个项目".因此,当给定时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]))
Run Code Online (Sandbox Code Playgroud)

相比之下,方法调用和索引操作将始终在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"]
Run Code Online (Sandbox Code Playgroud)

有多种方法可以删除分项:

%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
Run Code Online (Sandbox Code Playgroud)

我可能会for %a{3}<> { }在这种情况下使用; 它都比方法调用短,并且明确表示我们这样做纯粹是为了删除分项而不是强制.

虽然for |%a{3} { }也工作正常并且在视觉上很好,但它是唯一一个不优化向下简单地从Scalar容器中移除某些东西,而是制作一个中间Slip对象,这可能会使迭代减慢一点(尽管取决于如何循环正在做很多工作,很可能是噪音).


[1]根据我所写的内容,人们可能想知道为什么.perl可以恢复某些事项是逐项列出的事实.方法调用$foo.bar实际上是在做类似的事情$foo<>.^find_method('bar')($foo).然后,在a中method bar() { self },self绑定到调用该方法的东西,从其容器中删除.但是,可以写入method bar(\raw-self:) { }以完全按照提供的方式恢复它.


rai*_*iph 6

问题是Scalar容器做DWIM间接.

%a{3}绑定到一个Scalar容器.

默认情况下,如果你指的值或类型Scalar的容器,你真正访问值,或类型的值,包含在容器中.

相比之下,当您将Array容器称为单个实体时,您确实可以访问该Array容器,而不是手.

要查看你真正处理的.VAR是什么,使用哪个显示变量(或复合变量的元素)绑定的内容,而不是允许它绑定的任何容器假装它不在那里.

say %a{3}.VAR ;       # $["foo", "bar", "baz"]
say %a{3}.Array.VAR ; # [foo bar baz]
Run Code Online (Sandbox Code Playgroud)

这是一个匆忙的解释.我实际上正致力于一个专注于容器的帖子.

  • 我正在写一篇关于容器的帖子,所以每个人都能理解它们.它们美丽而简单,但需要仔细的写作才能实现.我希望这个周末能够做好准备.这里的核心问题是,数组是一个单一的东西吗?还是一堆东西?这两者都是.那你说'for array`是什么意思?P6说,如果你想这样做,每件事都可以作为一件事来处理.而且,无论您喜欢什么,每个复数都可以作为复数*或单个*处理.但你必须消除歧义.我可能会写'.say为|%a {3}`而不是`.say为%a {3} .Array`. (2认同)