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

时间:2018-05-11 20:07:46

标签: 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

2 个答案:

答案 0 :(得分:12)

此处观察到的差异与:

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

$ sigil可以被认为是“单个项目”。因此,当给予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上调用了,它的有趣工作实际上是在方法调用本身的行为中,它正在展开{{1} } 容器。 Scalar就像一个方法调用,它告诉你任何.WHAT容器里面的内容。

默认情况下,数组和散列的值是Scalar个容器,而这些容器又保存该值。但是,用于查看值的Scalar隐藏了该值,因为它与.WHAT内的内容有关。相比之下,Scalar [1]清楚地表明有一个项目:

.perl

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

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对象,这可能会使迭代速度降低一些(尽管取决于循环完成了多少工作,很可能是噪声)。

[1]根据我所写的内容,人们可能想知道为什么Slip可以恢复某些事项已被逐项列出的事实。方法调用.perl实际上正在执行$foo.bar之类的操作。然后,在$foo<>.^find_method('bar')($foo)中,method bar() { self }绑定到调用该方法的东西,从其容器中删除。但是,可以写self来完全恢复它。

答案 1 :(得分: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]

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