метод total и символ переменной Bag в Perl 6

Мы можем использовать метод total, чтобы узнать сумму всех весов в Bag.

> my $b = (1,2,1).Bag
Bag(1(2), 2)
> $b.total
3

Но если мы используем сигил % вместо $ для нашего Bag, мы получим сообщение об ошибке.

> my %b = (1,2,1).Bag
{1 => 2, 2 => 1}
> %b.total
No such method 'total' for invocant of type 'Hash'. Did you mean 'cotan'?
  in block <unit> at <unknown file> line 1

Если %b явно преобразуется в Bag до total, это работает:

> %b.Bag.total
3

Вопрос: раньше я думал, что с Set, Bag, SetHash и т. д. предпочтительнее использовать сигил %. Я ошибся?


person Eugene Barsky    schedule 03.05.2018    source источник


Ответы (2)


Привязать вместо назначения

my %b := (1,2,1).Bag;
say %b.total

Связывание (с :=) связывает правой стороны непосредственно в левую сторону. В этом случае значение, выполняющее роль Associative, привязывается к %b.

Или назначьте Bag

Присвоение (с помощью =) назначает (копирует) значения из правой стороны в контейнер слева.

Вы можете назначить после первой привязки к Bag следующим образом.

Непосредственно перед назначением декларатор my привязывает подходящий контейнер к объявленной переменной. По умолчанию это будет контейнер Hash, если переменная имеет сигил %.

Но вы можете указать переменную is, привязанную к другому типу контейнера, совместимому с его сигилом:

my %b is Bag = 1,2,1;
say %b.total

С этим заклинанием вам нужно использовать =, потому что к тому времени, когда встречается этот оператор, %b уже привязан к Bag, и теперь вам нужно назначить (скопировать) в Bag.

Таким образом, вы получаете простое предоставление списка значений (никаких явных ключей или Bag coercer/constructor не требуется), потому что = интерпретируется в соответствии с потребностями контейнера слева, а Bag выбирает интерпретацию RHS = как список ключей, количество вхождений которых важно для него.

person raiph    schedule 03.05.2018
comment
И если у меня есть BagHash и я хочу добавить новые элементы позже, должен ли я связывать или назначать? И как мне добавить новые элементы? - person Eugene Barsky; 03.05.2018
comment
Не уверен, надо бежать, ожидаю вернуться через час или два. - person raiph; 03.05.2018
comment
@EugeneBarsky my %b is BagHash = 1,2,1; %b{2} = 3; %b{1}++ - person Brad Gilbert; 03.05.2018
comment
@BradGilbert Спасибо, это работает! Но правильно ли я понимаю, что здесь нельзя использовать %b‹2› вместо %b{2}? - person Eugene Barsky; 03.05.2018
comment
@EugeneBarsky <a b c> — это сокращение от qw<a b c>, поэтому %h<a b c> — это сокращение от %h{qw<a b c>}. Поскольку вы имеете дело с Int 2, а не с Str "2", вы не можете использовать %h<2>. (Хеш по умолчанию использует ключи Str, поэтому в этом случае вы можете использовать %h<2>) - person Brad Gilbert; 03.05.2018
comment
@BradGilbert Спасибо, я этого не понял. Итак, %h{2} имеет 2 в качестве ключа, а %h<2> имеет '2', верно? - person Eugene Barsky; 03.05.2018
comment
@EugeneBarsky Это правильно. <> в этом контексте является конструкцией цитирования. - person jjmerelo; 04.05.2018

В Perl 6 назначение контейнера может быть принудительным, т. е. ценность контейнера. Видеть это:

my $b = (1,2,1).Bag;
say $b.^name; # Bag

my %haШ = (1,2,1).Bag;
say  %haШ.^name; # Hash

Привязка, с другой стороны, привязывает тип контейнера к содержащемуся элементу.

Итак, ответ: вы все еще можете использовать сигил, но, как сказал @raifh выше, используйте привязку, чтобы Bag или BagHash не превращались в простой Hash.

my %real-haШ := (1,2,1).Bag;
say %real-haШ.^name; # Bag
person jjmerelo    schedule 04.05.2018