Angenommen, ich habe eine Ganzzahl n
, die nur Werte in [0, 10]
annehmen wird. Sollte ich es als n::Int
deklarieren, um allgemein zu sein, als n::Int8
oder n::UInt8
, um sparsam zu sein oder n::Int64
für ein 64-Bit-System?
Bitte klären Sie die Gründe für einen Neuling, z. Stil, Leistung.
Hintergrund: Ich versuche Julia zu lernen und verirre mich schnell bei Wörtern wie type
, immutable
, syntactic sugar
! Ich glaube, ich habe das gelesen: https://docs.julialang.org/en/release-0.5/manual/integers-and-floating-point-numbers/
Es ist wichtig, zwei verschiedene Fälle zu unterscheiden.
Speicher: Wenn Sie einen Typ haben, der n
als eines seiner Felder oder als Wert in einem Array speichert, sollten Sie definitiv Int8
oder UInt8
verwenden. Selbst wenn der gespeicherte Speicherplatz für einen einzelnen Wert vernachlässigbar ist, können, wenn viele Instanzen Ihres Typs in einer Sammlung erstellt und gespeichert werden, die Platzeinsparungen schnell erheblich werden. Angenommen, Sie haben einen Foo
-Typ mit einem Feld n
, dann könnten Sie dies tun:
Wenn ein Wert dem n
-Feld eines Foo
-Objekts zugewiesen wird, wird es automatisch in UInt8
konvertiert und ein Fehler wird ausgelöst, wenn der Wert nicht korrekt konvertiert werden kann:
Wenn der Wert, der zugewiesen wird, bereits vom richtigen Typ ist, ist keine Überprüfung erforderlich, so dass kein Overhead entsteht.
Dispatch: Wenn Sie eine Methode einer Funktion schreiben, die n
als Argument verwendet, dann ist es nicht schädlich, wenn Sie eine lose Typ-Annotation für das Argument n
haben, da dies sinnvoll ist semantisch. In dem Fall, den Sie beschrieben haben, scheint es, dass jede Art von Integer-Wert sinnvoll wäre, so dass die Verwendung von n::Integer
wahrscheinlich angemessen wäre. Wenn Sie beispielsweise einen überprüften Konstruktor für Foo
-Objekte implementieren möchten, können Sie Folgendes tun:
Nun wird ein Fehler ausgegeben, wenn ein Wert außerhalb von [0, 10] angegeben wird:
%Vor% Diese Foo
-Konstruktion funktioniert für jede Art von Ganzzahl, prüft, ob sie im richtigen Bereich ist und konvertiert dann in UInt8
. Dies ist etwas restriktiver als der eingebaute Konstruktor für Foo
, der gerne irgendein -Argument des n
-Arguments nimmt und versucht, es in UInt8
zu konvertieren - selbst wenn das Argument nicht ist eines Integer-Typs. Wenn diese Art von Verhalten wünschenswert ist, könnten Sie die Typensignatur hier weiter zu n::Real
, n::Number
(oder sogar n::Any
, obwohl das übertrieben scheint) lösen.
Beachten Sie, dass es keinen Leistungsvorteil für eng typisierte Methodenargumente gibt - der spezialisierte Code für tatsächliche Argumenttypen wird trotzdem auf Anforderung generiert.
BEARBEITEN: beziehen Sie sich auf Stefans akzeptierte Antwort. Ich meine, dies ist eine Antwort auf die Verwendung von Typen in der Funktion Versand, aber in Wirklichkeit widersprach ich (wie ich explizit sage, dass Funktion Versand eigentlich Integer sein sollte).
Ich würde immer Int
verwenden, nur für die Allgemeinheit, aber es hängt davon ab, wie leistungsfähig Ihre Anwendung ist. Niemals Int64
, es sei denn, du benötigst es explizit. Viele Funktionen versenden auf Int
anstatt Integer
(obwohl die Empfehlung ist, nach abstrakten Typen zu versenden), was bedeutet, dass sie beim Übergeben eines UInt8 fehlschlagen (weil Int
ein Subtyp von Signed
und UInt
ist) ist nicht) so übereifrig mit Typen wird Probleme verursachen.
Als allgemeine Faustregel sollten Sie nie spezifischer mit Typen sein als Sie müssen.
Tags und Links types julia-lang