Этот код:
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
.A List
является неизменным.Таким образом, следующая строка:
@what = <does change> # Cannot modify an immutable Str (does)
Вместо этого вы могли бы написать:
constant @what = [<does not change>];
@what = <does change>;
say @what; # [does change]
A Scalar
работает как положено.
Itбудет потому что это не 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, или работает какое-то волшебство контейнера?
Это хороший вопрос, и я не собираюсь отвечать на него.