Rakudo Version 2020.01
Ich habe einen Wegwerfcode geschrieben und mich nicht darum gekümmert, eine Klasse zu implementieren, sondern nur einen Hash als Work-Alike verwendet. Ich fand ein überraschendes Verhalten bei Listen.
class Q1 {}
class R1 {
has Str $.some-str is required;
has @.some-list is required;
}
my $r1 = R1.new(
some-str => '…',
some-list => (Q1.new, Q1.new, Q1.new)
);
# hash as poor man's class
my $r2 = {
some-str => '…',
some-list => (Q1.new, Q1.new, Q1.new)
};
multi sub frob(R1 $r1) {
for #`(Array) $r1.some-list -> $elem {
$elem.raku.say;
}
}
multi sub frob(Hash $r2) {
for #`(List) $r2<some-list> -> $elem {
$elem.raku.say;
}
}
frob $r1;
# OK.
# Q1.new
# Q1.new
# Q1.new
frob $r2;
# got:
# (Q1.new, Q1.new, Q1.new)
# expected:
# Q1.new
# Q1.new
# Q1.new
frob(Hash …)
funktioniert wie erwartet, wenn ich anrufe .flat
oder .list
auf der Liste (obwohl es bereits eine Liste ist‽).
Ich habe versucht, einen minimalen Testfall zu erstellen, aber dies funktioniert identisch AFAICT.
for [Q1.new, Q1.new, Q1.new] -> $elem {
$elem.raku.say;
}
for (Q1.new, Q1.new, Q1.new) -> $elem {
$elem.raku.say;
}
Ich habe die Dokumentation zu List und Scalar mehrmals gelesen, kann aber aus meiner Beobachtung immer noch keinen Sinn machen. Warum muss ich die Liste im Hash speziell behandeln, aber nicht in der Klasse?
No such method 'raku' for invocant of type 'Q1'
wenn ich versuche, dies auszuführen.perl
: Vielleicht ist dein Rakudo nicht aktuell genug?Antworten:
for
führt keine Schleife über Einzelwerte durch.Wenn Sie etwas in einen skalaren Container legen, wird es aufgelistet.
Ein Element in einem Hash ist auch ein skalarer Container.
Wenn Sie also eine Liste in einen Hash einfügen, wird diese aufgelistet.
Wenn Sie also die Werte durchlaufen möchten, müssen Sie sie auflösen.
Sie können diesen skalaren Container vermeiden, indem Sie stattdessen binden.
(Dies verhindert, dass der
=
Operator an diesem Hash-Element arbeitet.)Wenn Sie bemerkt haben, dass Sie es im Klassenobjekt mit einem
@
Nicht definiert haben$
Wenn Sie es in ein geändert
$
und markiert habenrw
, funktioniert es wie im Hash-BeispielEs muss eine
$
Variable sein , sonst befindet es sich nicht in einem Scalar-Container.Es muss auch markiert
rw
werden, damit der Accessor den tatsächlichen Scalar-Container und nicht den de-itemized-Wert zurückgibt.quelle
Das hat nichts mit
[]
Versus zu tun()
. Dies hat mit dem Unterschied zwischen$
(Angabe eines Elements) und%
(Angabe eines Assoziativen) zu tun :Im Fall "b" wird ein Artikel empfangen . Wenn Sie versuchen, darüber zu iterieren, erhalten Sie 1 Iteration für dieses Element. Während Sie im Fall "a" angegeben haben, dass es sich um etwas Assoziatives handelt, das Sie möchten (mit dem
%
Siegel).Vielleicht ein klareres Beispiel:
Da
$a
es sich um ein Element handelt, erhalten Sie eine Iteration. Sie können angeben, dass Sie das zugrunde liegende Objekt iterieren möchten, indem Sie Folgendes hinzufügen.list
:Oder, wenn Sie mehr Leinen bekommen möchten, stellen Sie ein Präfix ein
@
:quelle
Nicht unbedingt eine Antwort, sondern eine Beobachtung: In Raku lohnt es sich, im Gegensatz zu Perl Klassen anstelle von Hashes zu verwenden:
Verwenden von Klassen und Objekten:
Die Verwendung von Klassen ist nicht nur schneller, sondern verhindert auch, dass Sie bei der Initialisierung Tippfehler machen, wenn Sie das
is required
Merkmal hinzufügen :Und es verhindert, dass Sie beim Zugriff Tippfehler machen:
quelle
FALLBACK
)