将Seq(Seq)分配给数组

时间:2019-06-05 20:15:07

标签: perl6

将Seq(Seq)分配给多个类型数组而不先将Seq分配给标量的正确语法是什么? Seq是否会以某种方式展平?失败:

class A { has Int $.r }

my A (@ra1, @ra2);

#create two arrays with 5 random numbers below a certain limit

#Fails: Type check failed in assignment to @ra1; expected A but got Seq($((A.new(r => 3), A.n...)
(@ra1, @ra2) =
   <10 20>.map( -> $up_limit {
        (^5).map({A.new( r => (^$up_limit).pick ) })
    });

2 个答案:

答案 0 :(得分:12)

TL; DR 绑定比赋值快,所以也许这是解决问题的最佳实践:

:(@ra1, @ra2) := <10 20>.map(...);

分配/复制

简化,您的无效代码为:

(@listvar1, @listvar2) = list1, list2;

在P6中,缀=表示将值列表从= 的右边分配/复制到一个或多个container变量=的左侧。

如果左侧的变量绑定到Scalar container,则它将接受一项。然后复制过程开始针对下一个容器变量。

如果左侧的变量绑定到Array container,则它将接受所有剩余值。因此,您的 first 数组变量同时接收list1list2。这不是你想要的。

简化,这是克里斯托夫的答案:

@listvar1, @listvar2 Z= list1, list2;

暂时将=放在一边,Zthe zip routine的中缀版本。就像(a physical zip在其左右连续配对参数。当与运算符一起使用时,该运算符应用于该对。因此,您可以将上述Z=读为:

@listvar1 = list1;
@listvar2 = list2;

工作完成。

但是将放入 Array容器需要:

  • 分别复制 容器一样多的单个列表项。 (在示例list1list2中的代码中,每个元素包含5个元素,因此总共要进行10个复制操作。)

  • 根据需要强制调整容器的大小以容纳物品。

  • 将项目所用的内存增加一倍(原始列表元素以及复制到Array元素中的重复元素)。

  • 检查每个项目的类型是否匹配元素类型约束。

分配通常比绑定要慢得多,而且占用的内存更多...

绑定

:(@listvar1, @listvar2) := list1, list2;

:=运算符binds右边的参数指向左边的任何内容。

如果左侧只有一个变量,那么事情就特别简单。绑定后,变量现在精确地指向右边的内容。 (这特别简单,快速-一种快速的类型检查就完成了。)

但是我们的情况并非如此。

Binding的左侧也接受独立的签名文字。我的答案中的:(...)是独立的Signature文字。

(签名通常附加到不带冒号前缀的例程。例如,在sub foo (@var1, @var2) {}中,(@var1, @var2)部分是附加到例程foo的签名。但是您可以看到,您可以分别编写一个签名,并在一对括号前面加上一个冒号,让P6知道它是一个签名。主要区别是签名中列出的任何变量都必须已经声明。)

当左侧有签名文字时,绑定将根据与接收例程签名的例程调用中的绑定参数相同的逻辑进行。 (实际上,它在编译器中执行相同的代码路径。)

因此,最终结果是变量获得了它们在此子对象中具有的值:

sub foo (@listvar1, @listvar2) { }
foo list1, list2;

这意味着效果与

相同
@listvar1 := list1;
@listvar2 := list2;

再次,就像克里斯托夫的回答一样,工作已经完成。

但是这次我们将避免上一节末尾描述的大部分分配开销。

答案 1 :(得分:11)

不确定是否是设计使然,但似乎发生的是两个序列都存储在@ra1中,而@ra2仍然为空。这违反了类型约束。

起作用的是

@ra1, @ra2 Z= <10 20>.map(...);