Ich habe bereits eine verwandte Frage here gestellt und die Antwort hat mein Problem behoben, aber ich habe ein allgemeineres Missverständnis, wie Kristall prüft Typen, da ich in ähnliches Problem laufe, wenn jemand mir helfen könnte, herauszufinden, dass ich wäre gut. Ich habe viele Dinge ausprobiert, die gut mit Ruby funktionieren würden, aber absolut nicht mit Crystal funktionieren (ich weiß, dass sie viele Unterschiede haben, aber ich bin vertrauter mit Ruby).Typüberprüfung in Crystal
Hier ist eine Klasse:
class Narray(T)
getter shape
getter values
@shape : Tuple(Int32, Int32) | Nil
def initialize(values : T)
@values = values
@type = T
@shape = set_shape
end
def set_shape
if (@type == Array(Array(Int32))) || (@type == Array(Array(Float64)))
return {values.size, values[0].size} # Line causing the error
elsif (@type == Array(Int32)) || (@type == Array(Float64))
return {1, @values.size}
end
end
def is_matrix?
if @values[0].is_a?(Array(Int32)) || @values[0].is_a?(Array(Float64))
return true
else
return false
end
end
end
ein Array zu definieren, sollte ich tun:
arr1 = Narray.new([1,2,3])
die durch set_shape
abzurufen, die Form des Feldes (ein Tupel, die die Anzahl laufen würde von Reihen und Anzahl von Spalten). Bei dieser Methode checke ich die if-Anweisung ein, wenn es sich um ein 2D-Array handelt oder nicht. Wenn jedoch die Zeile oben ausgeführt wird, bekomme ich diesen Fehler:
in script.cr:16: undefined method 'size' for Int32
return {values.size, values[0].size}
das ist genau das, was das erste if-Anweisung vermeiden sollte. Da ich ein 1D-Array initialisiere, sollte es nicht durch den .size
Teil gehen.
Ich bin mir ziemlich sicher, dass es eine triviale Erklärung ist, und dass es etwas ziemlich Grundlegendes gibt, das ich nicht bekommen habe, aber ich möchte es bekommen, anstatt ständig über dieses Thema zu stolpern.
Wie kann ich in Crystal nach Typ suchen, da die Art und Weise, wie ich benutze, nicht der richtige Weg ist? Ich habe versucht mit is_a?
, == Type
, mit der is_matrix?
Methode (die funktioniert gut und macht die Aufgabe zu bestimmen, ob es 2D oder 1D ist, aber immer noch durch den falschen Teil läuft).
EDIT: nach der ersten Antwort, ich habe die set_shape
Methode geändert:
def set_shape
if (@values.is_a? Array(Array(Int32))) || (@values.is_a? Array(Array(Float64)))
return {values.size, values[0].size}
elsif (@values.is_a? Array(Int32)) || (@values.is_a? Array(Float64))
return {1, @values.size}
end
end
Aber ich habe noch genau die gleichen Fehler
Vielen Dank für Ihre Antwort. Ich habe versucht, was Sie empfohlen haben, was @values Typ direkt bewertet, aber nicht funktioniert (siehe meine Bearbeitung, ich habe hinzugefügt, was ich versucht habe).Wenn du zwei verschiedene Arten hast, meinst du 2 Unterklassen? Idealerweise versuche ich, einen Typ zu erstellen, der die gleichen Fähigkeiten wie numpy ndarrays hat, die sehr praktisch sind. Und es scheint mir, dass ein Teil davon, warum es bequem ist, ist, weil es ein Typ für 1D/2D/Int/Float ist. Aber ich bin immer offen für Vorschläge und wenn Sie irgendwelche "Design" -Ratschläge für diese Klasse haben, wäre es großartig. –
Das Problem ist, dass Sie sich immer auf '@ values' beziehen und keine lokale Kopie davon machen 'Werte = @ Werte'. Der Typ wird für eine lokale Variable korrekt eingeschränkt, da sein Typ sich nicht ändert (er ist lokal für die Funktion), aber die Instanzvariable kann jederzeit von einem anderen Thread oder einer anderen Funktion geändert werden (es handelt sich um einen gemeinsamen Wert) Der Typ wird nicht durch den Aufruf "is_a?" eingeschränkt und bleibt die Union. –