Вот рабочий пример:
my %hash;
for 1..4 -> $i {
%hash{$i} = Array.new without %hash{$i};
%hash{$i}.push: $_ for ^$i;
}
say %hash; # OUTPUT: {1 => [0], 2 => [0 1], 3 => [0 1 2], 4 => [0 1 2 3]}
Но почему следующий подобный пример не работает?
my %hash is default(Array.new);
for 1..4 -> $i {
%hash{$i}.push: $_ for ^$i;
}
say %hash; # OUTPUT: {}
Это меня еще больше смущает, потому что следующий пример работает как положено:
my %hash is default(42);
for 1..4 -> $i {
%hash{$i}.=Str;
}
say %hash.raku; # OUTPUT: {"1" => "42", "2" => "42", "3" => "42", "4" => "42"}
Мне не сразу понятно, почему результатом второго примера является пустой хэш, однако использование is default таким образом не будет работать так, как вы хотите. Трейты применяются во время компиляции; таким образом, is default(Array.new), даже если бы он работал правильно, создал бы один экземпляр Array во время компиляции и повторно использовал бы его глобально. Итак, результат, который я ожидаю, будет примерно таким:
1 => [0 0 1 0 1 2 0 1 2 3], 2 => [0 0 1 0 1 2 0 1 2 3], 3 => [0 0 1 0 1 2 0 1 2 3], 4 => [0 0 1 0 1 2 0 1 2 3]}
То, что это не дает, это, вероятно, ошибка.
Однако благодаря автоживификации первый пример можно сократить до:
my %hash;
for 1..4 -> $i {
%hash{$i}.push: $_ for ^$i;
}
say %hash; # {1 => [0], 2 => [0 1], 3 => [0 1 2], 4 => [0 1 2 3]}
В любом случае массив создается автоматически при выполнении операции с массивом над неопределенным значением, что означает, что в такой ситуации нет смысла использовать is default.
Я не думаю, что RakuAST сам по себе что-то меняет. Черты реализованы как множественная отправка, выполняемая во время компиляции, поэтому к тому времени, когда мы достигнем обработчика признаков, мы уже получим значение, а не AST. Я действительно не понимаю, зачем нужен особый случай is default, когда уже есть черта will, которая идет с блоком, поэтому will default { ... } не нужен особый случай.
Я думаю, в RakuAST мы могли бы довольно легко рассматривать содержимое is default() как преобразователь и сгенерировать его для запуска во время выполнения с помощью специального дескриптора контейнера? У меня были случаи, когда я хотел принудительно указать значения хеша, например. быть родным массивом str, и это было бы удобно для этого.