«Инвокант метода« ASSIGN-KEY »должен быть экземпляром объекта» при использовании оператора присваивания - PullRequest
10 голосов
/ 23 февраля 2020

Ха sh с набранными ключами…

use v6;
class Foo {}
my Hash[Foo, Foo] $MAP;

my $f1 = Foo.new;
my $f2 = Foo.new;

$MAP{$f1} = $f2;

выдает ошибку:

Инверант метода 'ASSIGN-KEY' должен быть экземпляром объекта типа 'Hash [Foo, Foo] ', а не объект типа типа' Hash [Foo, Foo] '. Вы забыли «.new»?

Я считаю, что это вводит в заблуждение; в чем реальная ошибка и что я должен написать вместо этого?

Я уже пробовал сигилу % для переменной ha sh, которая тоже не работает.

Ответы [ 2 ]

7 голосов
/ 23 февраля 2020

В том виде, как вы его определили, $MAP на самом деле является ролью. Вам нужно создать (на самом деле, каламбур ) это:

class Foo {}
my Hash[Foo, Foo] $MAP;

my $map = $MAP.new;

my $f1 = Foo.new;
my $f2 = Foo.new;

$map{$f1} = $f2;
say $map;

Мертвая расплата здесь состояла в том, что классы не могут быть параметризованы , Роли делают.

Также:

say $MAP.DEFINITE; # False
say $map.DEFINITE; # True

Но на самом деле сообщение об ошибке было довольно информативным, вплоть до предложения использовать .new, как я здесь.

Мы можем сократить его до:

class Foo {}
my %map = Hash[Foo, Foo].new ;
%map{Foo.new} = Foo.new;
%map.say;

Выполняя определение из определения, нам не нужен промежуточный класс $ MAP.

6 голосов
/ 23 февраля 2020

TL; DR JJ ответ правильный, но объяснение оставило меня в замешательстве. В настоящее время я рассматриваю проблему, которую вы показывали, как сообщение об ошибке * ошибка / ошибка и / или сообщение об ошибке LTA.

say my Any       $Any;        # (Any)
say my Hash      $Hash;       # (Hash)
say my Hash[Int] $Hash-Int;   # (Hash[Int])
$Any<a>          = 42;        # OK
$Hash<a>         = 42;        # OK
$Hash-Int.new<a> = 42;        # OK
$Hash-Int<a>     = 42;        # must be an object instance, not a type object

Imo, это ошибка или почти такая же.

Ошибка / проблема применима и к массивам в том же сценарии:

say my Any       $Any;        # (Any)
say my Array     $Array;      # (Array)
say my Array[Int] $Array-Int; # (Array[Int])
$Any[42]           = 42;      # OK
$Array[42]         = 42;      # OK
$Array-Int.new[42] = 42;      # OK
$Array-Int[42]     = 42;      # Type check failed ... expected Array[Int] but got Array

Если это лучше всего считать notabug, то, возможно, сообщение об ошибке следует изменить. Хотя я согласен с JJ в том, что сообщение об ошибке действительно присутствует (когда вы понимаете, как работает raku и выясняете, что происходит), я думаю, что это, тем не менее, сообщение об ошибке LTA, если мы не изменим raku (do) на dwim.

С другой стороны, для меня не очевидно, как лучше всего улучшить сообщение об ошибке. И теперь у нас есть это ТАК. (см. мою точку зрения об этом в Является ли ... сообщение об ошибке LTA? в недавний ответ, который я написал .)

Другое решение

Я уже попробовал сигил % для переменной ha sh, которая тоже не работает.

JJ предоставил решение, которое инициализируется значением с явным .new. Но это снимает ограничение с переменной. Чтобы сохранить его:

class Foo {}
constant FooFoo = Hash[Foo:D,Foo:D];
my %foo is FooFoo;
%foo{Foo.new} = Foo.new;

В идеале constant не понадобится, и, возможно, однажды он не понадобится, но я думаю, что разбор признаков ограничен.

...