"Invocant der Methode 'ASSIGN-KEY' muss eine Objektinstanz sein", wenn der Zuweisungsoperator verwendet wird

10

Hash mit getippten Schlüsseln…

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

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

$MAP{$f1} = $f2;

erzeugt den Fehler:

Der Aufruf der Methode 'ASSIGN-KEY' muss eine Objektinstanz vom Typ 'Hash [Foo, Foo]' sein, kein Typobjekt vom Typ 'Hash [Foo, Foo]'. Hast du ein '.neues' vergessen?

Ich finde es irreführend; Was ist der wahre Fehler und was muss ich stattdessen schreiben?

Ich habe bereits das %Siegel für die Hash-Variable ausprobiert , das funktioniert auch nicht.

daxim
quelle
Was Sie anrufen, ist, dass $ MAP eine Klasse ist; OTOMH, ich würde sagen, es ist eine Rolle. Sie müssen es instanziieren. Aber lass mich nachsehen.
jjmerelo

Antworten:

7

In der Art, wie Sie es definiert haben, $MAPist eigentlich eine Rolle. Sie müssen es instanziieren (eigentlich Wortspiel ):

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

my $map = $MAP.new;

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

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

Das tote Werbegeschenk hier war, dass Klassen nicht parametrisiert werden können , Rollen schon.

Ebenfalls:

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

Aber eigentlich war die Fehlermeldung ziemlich informativ, bis hin zum Vorschlag .new, wie ich es hier tue.

Wir können es verkürzen auf:

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

Wenn wir die Definition ausführen, benötigen wir die $ MAP-Zwischenklasse nicht.

jjmerelo
quelle
6

Die Antwort von TL; DR JJ ist richtig, aber die Erklärung hat mich verwirrt. Ich betrachte das von Ihnen angezeigte Problem derzeit als Autovivifizierungsfehler / Fehler und / oder LTA-Fehlermeldung.

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 das ist ein Fehler oder ziemlich nah an einem.

Ein Fehler / Problem tritt auch für Arrays im selben Szenario auf:

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

Wenn es am besten als notabug angesehen wird, sollte möglicherweise die Fehlermeldung geändert werden. Obwohl ich JJ zustimme, dass die Fehlermeldung tatsächlich zutreffend ist (wenn Sie verstehen, wie Raku funktioniert und herausfinden, was los ist), denke ich, dass es dennoch eine LTA-Fehlermeldung ist, wenn wir Raku (do) nicht in dwim ändern.

Auf der packenden Hand ist mir nicht klar, wie man die Fehlermeldung am besten verbessern kann. Und jetzt haben wir dieses SO. (Siehe meinen Punkt dazu in Ist die ... Fehlermeldung LTA? in einer kürzlich von mir geschriebenen Antwort .)

Eine andere Lösung

Ich habe bereits das %Siegel für die Hash-Variable ausprobiert , das funktioniert auch nicht.

JJ hat eine Lösung bereitgestellt, die mit einem Wert mit einem expliziten Wert initialisiert wird .new. Dadurch wird jedoch die Einschränkung aus der Variablen entfernt. Um es zu behalten:

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

Im Idealfall constantwürde das nicht benötigt und vielleicht eines Tages auch nicht, aber ich denke, das Parsen von Merkmalen ist begrenzt.

Raiph
quelle