Bisher hat der Lehrplan nicht viel über Typen gesagt, aber offensichtlich gibt es sie in Julia:
julia> vals = (42, 4.3, π, "hello", 'Q')
(42, 4.3, π, "hello", 'Q')
julia> typeof(vals)
Tuple{Int64, Float64, Irrational{:π}, String, Char}
Wir haben die Typen nie festgelegt, aber Julia hat sie trotzdem zugewiesen.
types, die für sein Design zentral sind.Type Inference verwendet.Der JIT-Compiler schaut sich den (gesamten) Code an, sieht, wie eine Variable verwendet wird, und leitet einen passenden Standardtyp ab, der zu dieser Verwendung passt.
Sich auf die Typinferenz zu verlassen, ist für einfache Übungen in Ordnung, aber bei größeren Programmen brauchst du wahrscheinlich eine genauere Kontrolle.
Auf den meisten modernen Prozessoren hat eine Ganzzahl standardmäßig den Typ Int64.
Im Numbers-Konzept haben wir gesehen, dass ein Wert in einen bestimmten Typ umgewandelt werden kann, der nicht der Standardtyp ist.
julia> x = Int16(42)
42
julia> typeof(x)
Int16
Allerdings kann die Variable x weiterhin einem anderen Typ zugewiesen werden:
julia> x = "changed"
"changed"
julia> typeof(x)
String
Das ist type instability, was Folgendes bedeutet:
Stattdessen können wir den Typ von x mit dem Operator :: festlegen:
julia> y::Int16 = 42
42
julia> typeof(y)
Int16
julia> y = "changed"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int16
The function `convert` exists, but no method is defined for this combination of argument types.
Jetzt ist y vom Typ Int16, und das wird immer so bleiben.
So weiß der Compiler, wie viele Bytes er dafür reservieren muss, und kann den restlichen Code darauf optimieren, sich auf einen stabilen Typ zu verlassen.
Damit ähnelt die Variable mehr oder weniger denen in einer statisch typisierten Sprache wie C.
Int64, Int16, String, Char: Woher "kommen" diese Typen?
In vielen objektorientierten (OO) Sprachen ist jeder Typ eine Klasse, die Vererbung ordnet sie in einer Klassenhierarchie an, und Klassenmethoden definieren das Verhalten.
Java und Ruby sind offensichtliche Beispiele für dieses Muster, aber selbst Python funktioniert intern ähnlich.
Julia hat keine Klassen.
Der dokumentierte Grund dafür ist, dass OO-Features den JIT-Compiler stören und die Laufzeitleistung beeinträchtigen.
Und trotzdem, schau dir diesen Code an:
julia> y::Int16 = 42
42
julia> typeof(y)
Int16
julia> supertype(Int16)
Signed
julia> supertypes(Int16)
(Int16, Signed, Integer, Real, Number, Any)
Ein paar Details dazu:
Int16 ist ein Typ, und wir können Variablen dieses Typs erstellen.Int16 ist ein Untertyp von Signed, und die Funktion supertype() zeigt uns das.Integer, Real und Number bis hin zu Any an der Spitze reicht, und subtypes() listet diesen Zweig der Hierarchie für uns auf.Alle Zweige enden in Any, das einzigartig darin ist, sein eigener Obertyp zu sein.
julia> supertypes(String)
(String, AbstractString, Any)
julia> supertype(Any)
Any
Julia hat also keine class-Hierarchie, aber es hat eine type-Hierarchie.
Irgendwann werden wir versuchen, zu ergründen, wie das funktioniert, aber zuerst gibt es noch viel mehr zu entdecken.
Wir können mit typeof() wie üblich auf Gleichheit prüfen.
julia> typeof(11)
Int64
julia> typeof(11) == Int64
true
julia> typeof(11) == Number
false
Die Typgleichheit muss exakt sein, denn diese Art des Vergleichs kennt die Typhierarchie nicht.
Flexibler ist isa: Es sagt uns, ob ein Wert denselben Typ wie ein Vergleichswert hat oder einen Untertyp davon.
Es kann sowohl in Funktionsform als auch in Infixform verwendet werden.
julia> 12 isa Int64
true
julia> 12 isa Number
true
julia> isa(12, Number)
true
julia> 12 isa String
false
Beachte, dass isa links einen value erwartet, nicht einen type.
Wenn du zwei Typen auf diese Weise vergleichst, bekommst du unerwartete Ergebnisse.
Der richtige Operator ist <:, den wir in zukünftigen Konzepten noch viel häufiger sehen werden.
julia> Int64 isa Number ## Don't do this!
false
julia> Int64 <: Number
true
Wir haben gesehen, dass die Typhierarchie eine Baumstruktur bildet (im Sinne der Informatik, mit der Wurzel oben).
Jedes Element im Baum ist ein node, und diese lassen sich in Kategorien einteilen:
abstract.concrete.julia> subtypes(Integer) # an abstract type
3-element Vector{Any}:
Bool
Signed
Unsigned
julia> subtypes(Int64) # a concrete type
Type[]
Das ist ein wichtiger Unterschied, denn nur konkrete Typen können als Variablen instantiated werden.
julia> a::Int16 = 42
42
julia> typeof(a)
Int16
julia> b::Integer = 42
42
julia> typeof(b)
Int64
Beachte, dass der Versuch, einen abstrakten Typ zu verwenden, (in diesem Fall) keine Fehlermeldung erzeugt, aber der Compiler erstellt einen passenden konkreten Typ: Int64 statt Integer.
In dieser Übung machst du ein wenig Data Engineering, indem du einige Notendaten vorverarbeitest. Eine Schule mit sehr, sehr, sehr vielen (zu vielen?) Schülern versucht, eine Datenanalyse der von den Schülern erhaltenen Noten durchzuführen, und möchte das effizient machen. Die Idee ist also, die Daten zu minimieren und zu ordnen.
Die Notenskala reicht normalerweise von 0 bis 10, daher ist es am effizientesten, einen Datentyp mit nur acht Bits pro Note zu verwenden.
UInt8 umwandeln.Int8 umwandeln.Sobald du die Funktion zum Umwandeln der Noten implementiert hast, musst du eine weitere schreiben, die die Sammlungen verarbeitet, in denen sie gespeichert sind, indem sie die Noten herabstuft und sie in absteigender Reihenfolge zurückgibt.
Vectors, um ihre Noten zu speichern, weil sie bei ihren Daten sehr sorgfältig sind.Sets, die unsortiert sind, um ihre Noten zu speichern, weil sie etwas fauler sind.In beiden Funktionen musst du ungültige Eingaben behandeln, indem du einen MethodError auslöst.
Die Ausnahmebehandlung wird in einem späteren Konzept behandelt, daher kannst du für diese Übung die folgende Syntax verwenden:
throw(MethodError(f, args))
Dabei ist f die Funktion und args ein Tupel der in die Funktion eingegebenen Argumente.
Bei der Funktion demote(n) ist f gleich demote und args gleich (n,):
throw(MethodError(demote, (n,)))
Implementiere die Methode demote(n).
Float64 sollte sie auf die nächste ganze Zahl aufrunden und einen Datentyp UInt8 zurückgeben.Integer sollte sie dieselbe Ganzzahl in einem Datentyp Int8 zurückgeben.julia> demote(4.2)::UInt8
5
julia> demote(4)::Int8
4
julia> demote("hi")
MethodError: no method matching demote(::String) #output truncated
Implementiere die Methode preprocess(coll).
Vector sollte sie alle Zahlen herabstufen und den Vektor umkehren.Set sollte sie alle Zahlen herabstufen und einen sortierten Vektor in absteigender Reihenfolge zurückgeben.julia> preprocess([1, 2, 3])
3-element Vector{Int8}:
3
2
1
julia> preprocess(Set([2.2, 5.8, 3.4]))
3-element Vector{UInt8}:
6
4
3
julia> preprocess(42)
MethodError: no method matching preprocess(::Int64) #output truncated
Melde dich bei Exercism an, um Julia mit 35 Konzepte128 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.