这段代码:
constant %what = { doesn't => 'change' };
%what = { will => "change" }
应该说“不能修改不可变哈希”。
谁这么说的?我的意思是修辞上的,而不是粗鲁的。我明白为什么你会这样想,但重要的是要小心使用“应该”这个词,因为它暗示某些权威会这样说,例如规范、设计文档或某人的常识,或者随便。
根据当前规范和 Rakudo 实现,constant foo ... 所做的是永久(不断)绑定 foo 到某个特定的“值”。
如果那个“值”是一个容器,那么foo 会一直引用那个容器。 (是的,一个容器可以是一个“值”,对于一些适合这里的“值”的定义。)
所以你上面的代码已经改变了该容器中包含的元素 within,也就是说,根据规范,完美的 cromulent:
say %what; # {will => change}
与此同时,警告消息合法地提到了哈希构造函数的无用使用,并指出:
did you mean := instead?
如果你尝试这样做:
constant %what = { doesn't => 'change' };
%what := { will => "change" }
你得到:
Cannot use bind operator with this left-hand side
因为,正如已经确定的那样,%what 是一个编译时常量永久绑定到在编译时创建和初始化的哈希以及那个方面 - %what 到那个特定的永久绑定哈希 -- 在此程序运行期间无法更改。
Positionals 有几乎相同的问题,但错误是不同的。在这种情况下,它不能修改一个不可变的,而是一个Str:
constant @what = <does not change>;
@what = <does change> # Cannot modify an immutable Str (does)
这有点不同。 constant 声明绑定,无论您写的是 = 还是 :=。所以常量声明等价于:
constant %what := { doesn't => 'change' }
constant @what := <does not change>;
第一行将%what 绑定到{ doesn't => 'change' },这是一个可变的Hash。
第二行将@what 绑定到<does not change>,这是一个不可变的List。
你可以改为:
constant @what = [<does not change>];
@what = <does change>;
say @what; # [does change]
Scalar 按预期工作。
不完全是。
标量(小写,通用术语):
constant $scalar = 42;
$scalar = 99; # Cannot assign to an immutable value
记住constant总是绑定,上面的代码类似:
my $scalar := 42;
$scalar = 99; # Cannot assign to an immutable value
但Scalar 在此上下文中的工作方式与其他容器相同:
constant $scalar = $ = 42;
$scalar = 99; # OK
(除非你想惹恼别人,否则不要写那样的代码。)
这是 LTA 错误消息的情况,还是某种容器魔法在起作用?
这是一个很好的问题,我不会尝试回答。