无用的哈希编写器,还是不能修改不可变的哈希?

时间:2019-03-17 19:42:26

标签: perl6

此代码:

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错误消息的案例,还是我在这里缺少的一些容器魔术?

1 个答案:

答案 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,则该绑定到该ListList是不可变的。因此,下一行变为:

@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错误消息的情况,还是某种容器魔术在起作用?

这是一个很好的问题,我不会尝试回答。