Заголовок вашего вопроса указывает на ошибку.Этот ответ покрывает ошибку, а также другие неявные и явные вопросы, которые вы задали.
Фон
терпит неудачу с некоторым изумлением: «Невозможно присвоить неизменное значение».
Я думаю, что это ошибка.Давайте начнем с некоторого кода, который работает:
my $a = 42;
say $a; # 42
say WHAT $a; # (Int) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 42; # works fine
В объявлении my
1013 * связывается с новым Scalar
контейнером .Контейнер Scalar
обычно скрывается.Если вы спросите WHAT
type $a
is, вы на самом деле получите тип значения, в настоящее время присвоенного скаляру (значение, которое оно «содержит»).Вам нужно VAR
, чтобы получить доступ к контейнеру BOUND до $ a.Когда вы присваиваете =
контейнеру Scalar
, вы копируете присвоенное значение в контейнер.
role foo {}
$a does foo; # changes the VALUE currently ASSIGNED to $a
# (NOT the VARIABLE that is BOUND to $a)
say $a; # 42 mixed in `foo` role is invisible
say WHAT $a; # (Int+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 99; say $a; # 99
does
смешивает роль foo
в 42
.Вы все еще можете присвоить $ a, потому что он все еще привязан к Scalar
.
Обратите внимание, как эти два использования does
имеют очень разные эффекты:
my $a does foo; # mixes `foo` into VARIABLE bound to $a
$a does foo; # mixes `foo` into VALUE assigned to $a
Ошибка
$a.VAR does foo; # changes VARIABLE currently BOUND to $a (and it loses the 42)
say $a; # Scalar+{foo}.new VALUE currently ASSIGNED to $a
say WHAT $a; # (Scalar+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar+{foo}) type of VARIABLE currently BOUND to $a
$a = 'uhoh'; # Cannot assign to an immutable value
does
смешивает роль foo
с Scalar
, привязанным к $ a.Кажется, что Scalar
с миксином больше не работает как контейнер, и назначение не выполняется.
В настоящее время это выглядит как ошибка.
my $b does foo; # BINDS mixed in VARIABLE to $b
$b = 'uhoh'; # Cannot assign to an immutable value
my $b does foo
имееттот же результат, что и my $b; $b.VAR does foo;
, так что вы получите ту же проблему, что и выше.
Другие вещи, которые вас смущают
my $a = 'GAATCC';
$a does DNA;
.say for $a;
, просто печатает строку, не обращая никакого внимания наIterable
mixin.
Поскольку $a
VARIABLE по-прежнему привязан к Scalar
(как объяснено в разделе Background выше), VALUE, который теперь имеетDNA
смешанная роль не имеет значения для процесса принятия решения for
, который используется для вызова метода .iterator
его аргумента .
Давайте назовем его тогда явно ...печатает значение $a.iterator
без фактического вызова функции:
.say for $a.iterator;
Ну, это действительно вызывает метод DNA
вашей роли *1081*.Но у этого есть еще один .iterator
вызов в конце self.comb
, возвращенного методом iterator
вашей роли DNA
, так что вы .say
используете этот вторичный .iterator
.
Решения, которые работают сегодня
Я думаю, что ответ Брэда хорошо охватывает большинство ваших вариантов.
И я думаю, что ваша хорошая does DNA
сущность так же хороша, как и онас сегодняшним P6, если вы хотите использовать $
sigil.
Решение, которое может однажды сработать
В идеальном мире вся прелесть в дизайне P6 будет полностью реализована в6.c
и реализация компилятора Rakudo в Perl 6. Возможно, это будет включать возможность написать это и получить то, что вы хотите:
class DNA is Scalar does Iterable { ... }
my $a is DNA = 'GAATCC';
.say for $a;
Код ...
будет примерно таким же, как у васв вашей сути, за исключением того, что класс DNA
будет скалярным контейнером, и поэтому вместо метода new
будет использоваться метод STORE
или аналогичный, который назначит переданное значение атрибуту $!value
или некоторому такому, когдазначение было присвоено контейнеруиспользуя =
.
Но вместо этого вы получаете:
is trait on $-sigil variable not yet implemented. Sorry.
Таким образом, наиболее близким сегодня к идеалу = 'string'
для изменения $a
является привязка с помощью := DNA.new('string')
как вы делали в своей сути.
Обратите внимание, что вы можете связывать произвольные составные контейнеры с @
и %
переменными сигил.Таким образом, вы можете видеть, как все в конечном итоге должно работать.