绑定到例程参数的严格类型检查

jjm*_*elo 7 perl6

具有以下常规定义

sub bar( Int @stuff ) {
    return [+] @stuff;
}
Run Code Online (Sandbox Code Playgroud)

以下两行均失败:

say bar( ^3 );
say bar( [1,2,3] );
Run Code Online (Sandbox Code Playgroud)

有错误

Type check failed in binding to parameter '@stuff'; 
expected Positional[Int] but got Array ($[1, 2, 3])
Run Code Online (Sandbox Code Playgroud)

但是,使用相同的定义分配变量

my Int @works = [1,2,3] ;
say bar( @works );
Run Code Online (Sandbox Code Playgroud)

显然,变量分配和参数绑定不能以完全相同的方式工作,但这是因为类型检查很严格吗?
还是还有其他机制在起作用?

Jon*_*ton 11

分配是一项复制操作。当我们说:

my @a = @b;
Run Code Online (Sandbox Code Playgroud)

然后:

  1. 从获得一个迭代器 @b
  2. 迭代它,将每个值分配给一个插槽 @a

这就是为什么将来分配到@b(或pushes,或pops等)不会影响的原因@a。(顺便说一句,这也意味着my @a = [1,2,3]相当浪费,因为它构造了一个匿名对象Array,只能对其进行迭代,然后立即将其留给GC使用。)

当我们有:

my @a = 1, 2, 3;
my Int @b = @a;
Run Code Online (Sandbox Code Playgroud)

然后,对每个分配到的插槽中进行类型检查@b。重要的是价值观。当然,我们必须进行O(n)类型检查,但是=平均而言,语义意味着我们仍在进行O(n)操作。

相比之下,绑定是别名操作。它使符号引用成为值。它是O(1)操作。如果我们有:

my @a = 1, 2, 3;
my Int @b := @a;
Run Code Online (Sandbox Code Playgroud)

然后它必须失败,因为@a它没有受到适当的限制。我们不能仅仅@a检查它的值是Int; 一方面,它会改变操作的复杂性,使代码的性能难以推断,而且以后还@a可以例如1.5将其分配给它,从而使类型约束@b变得毫无意义,因为它使别名成为别名。一样。

参数传递通过绑定起作用,因此在问题中观察到的效果。