Πολλές γλώσσες έχουν έναν τρόπο, όπως το null ή το none, για να δηλώσουν μια τιμή που δεν υπάρχει.
Επειδή η Julia είναι σχεδιασμένη να χειρίζεται μεγάλους όγκους (συχνά ακατάστατων) δεδομένων, έχει πολλαπλές μορφές ανυπαρξίας.
Ο γενικός στόχος είναι να επισημαίνονται οι τιμές που λείπουν ή είναι ύποπτες μόλις τις συναντήσουμε, και μετά να συνεχίζουμε χωρίς να πετάγεται κάποια εξαίρεση.
nothingΑν μια τιμή πραγματικά δεν υπάρχει, την αντιπροσωπεύει το nothing. Αυτό είναι μάλλον πιο κοντά σε αυτό που κάνει η C (NULL) ή η Python (None).
julia> n = nothing
julia> isnothing(n)
true
julia> typeof(n)
Nothing
Έτσι, το nothing είναι μια μοναδική τιμή τύπου Nothing και μπορούμε να το ελέγξουμε.
Μια συνηθισμένη χρήση του nothing είναι ως τιμή επιστροφής (ή μη-τιμή) για συναρτήσεις που χρησιμοποιούνται μόνο για τις παρενέργειές τους (εκτύπωση, ρύθμιση δικτύου ή ό,τι άλλο).
missingΣε περιπτώσεις όπου μια τιμή υπάρχει θεωρητικά αλλά δεν ξέρουμε ποια είναι, χρησιμοποιείται το missing. Για παράδειγμα, όταν μετράμε οχήματα που κινούνται σε έναν δρόμο, οι ανθρώπινοι παρατηρητές μπορεί να χρειαστούν διάλειμμα ή οι αυτόματοι αισθητήρες να χαλάσουν, αλλά η κυκλοφορία συνεχίζει να ρέει.
Έτσι, το missing είναι ένα σύμβολο κράτησης θέσης, που προειδοποιεί τον άνθρωπο ότι πρέπει να αποφασίσει πώς θα χειριστεί αυτό το κενό στα δεδομένα.
julia> mv = [1, 2, missing]
3-element Vector{Union{Missing, Int64}}:
1
2
missing
julia> typeof(mv)
Vector{Union{Missing, Int64}} (alias for Array{Union{Missing, Int64}, 1})
julia> ismissing.(mv) # broadcast function, displays as 1 for true, 0 for false
3-element BitVector:
0
0
1
Λίγες άλλες γλώσσες έχουν αυτή τη δυνατότητα ενσωματωμένη, αλλά κοντινά ανάλογα είναι το NA στη R ή το NULL στη SQL.
Ο τύπος του διανύσματος στο παραπάνω παράδειγμα ορίζεται ως Union{Missing, Int64}, που έχει κάποια ομοιότητα με τύπους όπως το Option ή το Maybe σε άλλες γλώσσες.
Οι εκφράσεις συνήθως επιστρέφουν missing από προεπιλογή αν υπάρχουν τιμές missing.
Αν θέλεις να αγνοηθούν αυτές οι τιμές, χρησιμοποίησε τη συνάρτηση skipmissing() για να το κάνεις ρητό:
julia> mv = [1, 2, missing]
3-element Vector{Union{Missing, Int64}}:
1
2
missing
julia> sum(mv) # missing in, missing out
missing
julia> skipmissing(mv)
skipmissing(Union{Missing, Int64}[1, 2, missing])
julia> collect(skipmissing(mv))
2-element Vector{Int64}:
1
2
julia> sum(skipmissing(mv)) # functions like sum() can work with iterators
3
Επειδή το skipmissing δημιουργεί έναν iterator, τύλιξέ το σε collect() αν χρειάζεσαι ένα διάνυσμα.
Μερικές φορές είναι χρήσιμο να αντικαταστήσεις τις τιμές missing με κάποια προεπιλεγμένη τιμή.
Η μακροεντολή @coalesce() είναι χρήσιμη γι' αυτό, καθώς επιστρέφει την πρώτη τιμή που δεν είναι missing (ή missing αν δεν υπάρχει τίποτα άλλο).
julia> str = ["I", "exist", missing]
3-element Vector{Union{Missing, String}}:
"I"
"exist"
missing
julia> [@coalesce(s, "-") for s in str]
3-element Vector{String}:
"I"
"exist"
"-"
NaNΣυντόμευση του "Not a Number", το NaN επισημαίνει ένα πρόβλημα υπολογισμού σε περιπτώσεις όπου περίμενες έναν αριθμό.
julia> v = [0, 1, -1]
3-element Vector{Int64}:
0
1
-1
julia> v / 0
3-element Vector{Float64}:
NaN
Inf
-Inf
julia> sum(v / 0)
NaN
Οποιοσδήποτε υπολογισμός σε δεδομένα που περιέχουν NaN θα δώσει αποτέλεσμα NaN.
Προς το παρόν δεν υπάρχει κάποια ειδική συνάρτηση για να αφαιρείς τιμές NaN, αλλά η τυπική συνάρτηση filter() μπορεί να το κάνει αρκετά απλά.
Μόνο οι τιμές για τις οποίες κάποια δεδομένη συνθήκη είναι true θα αντιγράφονται στον πίνακα αποτελεσμάτων:
julia> filter(!isnan, [1, 2, NaN])
2-element Vector{Float64}:
1.0
2.0
Αυτό είναι κάτι που πιθανότατα θα χρησιμοποιείς λιγότερο συχνά. Εξαιρέσεις περιλαμβάνουν:
struct) με μη αρχικοποιημένα πεδία.
Η Julia συνήθως προσπαθεί να χρησιμοποιήσει προεπιλεγμένες τιμές, αλλά μπορεί να το κάνει μόνο αν έχει αρκετές πληροφορίες για να συμπεράνει τον τύπο του πεδίου.undef μπορεί να είναι μια ευέλικτη και αποδοτική προσέγγιση.
Αυτό έχει χρησιμοποιηθεί, για παράδειγμα, σε λύσεις της κοινότητας για την άσκηση Circular Buffer (μια προχωρημένη τεχνική, αλλά βαθμολογείται ως δύσκολη άσκηση).Το να πάρεις αποτέλεσμα undef από μια προσπάθεια πρόσβασης σε μια τιμή είναι κατάσταση σφάλματος, που συνήθως επισημαίνεται με ένα UndefRefError.