[注意:我根据旧版本的 Rakudo 提出了这个问题。正如在接受的答案中所解释的,令人困惑的输出是 Rakudo 错误的结果,这些错误现已得到解决。我留下了下面 Q 的原始版本以供历史参考。]
Raku 有时会禁止重新绑定;以下两行
sub f($a) { $a := 42 }
my \var = 'foo'; var := 'not-foo';
产生编译时错误:
===SORRY!=== Error while compiling
Cannot use bind operator with this left-hand side
然而,Raku 允许在很多很多情况下重新绑定——包括许多让我大吃一惊的情况。以下所有成功重新绑定;每个say
输出not-foo
。
my Any \a = 'foo';
say a := 'not-foo';
my Any $b := 'foo';
say $b := 'not-foo';
my @c := ('foo', 'foo');
say @c := ('not-foo', 'not-foo');
my @d is List = ('foo', 'foo');
say @d := ('not-foo', 'not-foo');
my %e := (:foo<foo>);
say %e := (:not-foo<not-foo>);
sub fn1(Any \a) { a := 'not-foo'; say a }
fn1 'foo';
sub fn2(Any $b) { $b := 'not-foo'; say $b }
fn2 'foo';
sub fn3(@c) { @c := ('not-foo', 'not-foo'); say @c }
fn3 ('foo', 'foo');
sub fn4(+@d) { @d := ('not-foo', 'not-foo'); say @d }
fn4 ('foo', 'foo');
sub fn5(@d is raw) { @d := ('not-foo', 'not-foo'); say @d }
fn5 ('foo', 'foo');
my ($one-foo, $two-foo) := ('foo', 'foo');
$one-foo := 'not-foo';
say $one-foo;
my \foo = 'foo';
say MY::<foo> := 'not-foo';
sub foo-fn { 'foo' }
MY::<&foo-fn> := { 'not-foo' }
say foo-fn;
my $absolutely-foo = 'foo';
sub fn6 { CALLER::<$absolutely-foo> := 'not-foo';}
fn6;
say $absolutely-foo;
因此,如果满足以下任一条件,目前似乎允许对任何名称重新绑定,无论是否有印记:
- 该名称具有任何显式类型约束(包括由或sigils
Any
施加的类型约束),或@
%
- 重新绑定使用限定名称。
这种重新绑定当前发生在声明的变量和参数上,并且包括不是rw
或的参数copy
。正如最后一个示例所示,它甚至允许以(似乎?)违反词法范围的方式重新绑定。(该示例基于带有注释的 Roast 测试-- legal?
,这表明我可能至少不是唯一一个发现这种行为令人惊讶的人!虽然测试重新绑定了一个is dynamic
变量——在某些方面,上面的行为甚至更多奇怪)。
据我所知,唯一不能使用其中一种方法重新绑定的名称是那些声明为constant
.
所以四个问题:
- 我是否正确描述了当前的行为?[编辑:也就是说,我上面列出的两条规则是否正确描述了当前行为,或者正确的描述是否需要其他/附加规则?]
- 这种行为是否正确/有意/符合规范?(尽管存在S03-binding,但我发现重新绑定的情况非常少)。
- 如果这种行为不是故意的,那么重新绑定的规则应该是什么?
- 有什么方法可以告诉 Raku“不要将这个名字重新绑定到一个新的值,不是真的,我的意思是它”?
(这个问题取代了我之前的问题,在我意识到重新绑定名称是多么容易之前,我问过这个问题;我正在关闭它以支持这个问题。另一个相关问题:禁止无符号变量是否有目的或好处rebinding?,它讨论了一些设计权衡,假设无符号变量不能被重新绑定,这与上面的几个示例相反。)