此代码:
constant %what = { doesn't => 'change' };
%what = { will => "change" }
应该按照“无法修改不可变的哈希值”的方式进行说明。但是,它说:
Potential difficulties:
Useless use of hash composer on right side of hash assignment; did you mean := instead?
位置问题几乎相同,但错误有所不同。在这种情况下,它不能修改不可变,而只能修改Str:
constant @what = <does not change>;
@what = <does change> # Cannot modify an immutable Str (does)
标量按预期工作。这是LTA错误消息的案例,还是我在这里缺少的一些容器魔术?
答案 0 :(得分:7)
此代码:
constant %what = { doesn't => 'change' };
%what = { will => "change" }
应该说“不能修改不可变的哈希”。
谁这么说?我的意思是修辞,而不是粗鲁的。我得到你为什么这样的理解,但是要小心使用“应该”一词很重要,因为它暗示着某些权威机构是这样说的,例如规范或设计文件或某人的常识或...
根据当前规范和Rakudo实现,constant foo
所做的工作是使foo
在程序执行过程中始终引用某些特定的“值”。如果该“值”是一个容器,则foo
始终引用该容器。 (是的,对于“值”的某些定义,容器可以是“值”。)
因此,您上面的代码愉快地更改了该容器的内容 :
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
与该特定哈希的绑定可以在此程序运行期间不能更改。
位置问题几乎相同,但错误有所不同。在这种情况下,它不能修改不可变,而只能修改Str:
constant @what = <does not change>;
@what = <does change> # Cannot modify an immutable Str (does)
有点不同。不管您写constant
还是=
,:=
声明都会绑定。因此,第一行等效于:
constant @what := <does not change>;
这可能更清楚地显示正在发生的事情。默认情况下,@
符号创建一个Array
。但是,如果您将它们 bind 绑定到List
,则该绑定到该List
。 List
是不可变的。因此,下一行变为:
@what = <does change> # Cannot modify an immutable Str (does)
您可以改写:
constant @what = [<does not change>];
@what = <does change>;
say @what; # [does change]
Scalar
可以正常工作。
这是因为它不是Scalar
。相反,您将说的是标量,例如标量Int
:
my $foo = 42; say $foo.VAR.^name; # Scalar
constant $bar = 42; say $bar.VAR.^name; # Int
在右侧提到非匿名Scalar
会产生其包含的值。相反,任何在右侧提到复合容器的人都会引用该容器。
匿名Scalar
还会产生对容器的引用,而不是其值:
constant $foo = $;
$foo = 42;
say $foo; # 42
这是LTA错误消息的情况,还是某种容器魔术在起作用?
这是一个很好的问题,我不会尝试回答。