这段代码:
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错误信息的情况,还是我在这里工作的一些容器魔法?
这段代码:
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
它就会绑定到那个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错误消息的情况,还是某些容器魔法起作用?
这是一个很好的问题,我不会尝试回答。