无用的哈希作曲家,还是无法修改不可变哈希?

问题描述 投票:4回答:1

这段代码:

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错误信息的情况,还是我在这里工作的一些容器魔法?

perl6
1个回答
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。但是如果你绑定到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错误消息的情况,还是某些容器魔法起作用?

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

© www.soinside.com 2019 - 2024. All rights reserved.