Molti linguaggi hanno un modo, come null o none, per indicare un valore inesistente.
Poiché Julia è progettata per gestire grandi volumi di dati (spesso disordinati), ha diverse forme di assenza di valore.
L'obiettivo generale è segnalare i valori mancanti o sospetti quando li si incontra, per poi continuare senza sollevare un'eccezione.
nothingSe un valore non esiste davvero, è rappresentato da nothing. È probabilmente la cosa più vicina a quello che farebbero C (NULL) o Python (None).
julia> n = nothing
julia> isnothing(n)
true
julia> typeof(n)
Nothing
Quindi nothing è un valore singleton di tipo Nothing, e possiamo verificarlo.
Un uso comune di nothing è come valore restituito (o non-valore) per le funzioni che servono solo per i loro effetti collaterali (stampa, configurazione di rete o quant'altro).
missingPer le situazioni in cui un valore esiste in teoria, ma non sappiamo quale sia, si usa missing. Per esempio, quando si contano i veicoli che viaggiano su una strada, gli osservatori umani potrebbero aver bisogno di una pausa o i sensori automatici potrebbero guastarsi, ma il traffico continua a scorrere.
Quindi missing è un segnaposto che avverte gli esseri umani che devono decidere come gestire questa lacuna nei dati.
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
Pochi altri linguaggi hanno questa funzionalità integrata, ma analoghi simili sono NA in R o NULL in SQL.
Il tipo del vettore nell'esempio precedente è Union{Missing, Int64}, che ha una certa somiglianza con tipi come Option o Maybe di altri linguaggi.
Di solito le espressioni restituiscono missing per impostazione predefinita se sono presenti valori missing.
Se vuoi che questi valori vengano ignorati, usa la funzione skipmissing() per renderlo esplicito:
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
Poiché skipmissing crea un iteratore, avvolgilo in collect() se ti serve un vettore.
A volte è utile sostituire i valori missing con un valore predefinito.
La macro @coalesce() è utile a questo scopo, perché restituisce il primo valore non mancante (o missing se non c'è nient'altro).
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"
"-"
NaNNaN, abbreviazione di «Not a Number», segnala un problema di calcolo nelle situazioni in cui ci si aspettava un numero.
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
Qualsiasi tipo di calcolo su dati che includono un NaN darà come risultato NaN.
Al momento non esiste una funzione speciale per rimuovere i valori NaN, ma la funzione standard filter() può farlo in modo piuttosto semplice.
Solo i valori per cui una data condizione è true vengono copiati nell'array risultante:
julia> filter(!isnan, [1, 2, NaN])
2-element Vector{Float64}:
1.0
2.0
Questo è qualcosa che probabilmente userai meno spesso. Le eccezioni includono:
struct) con campi non inizializzati.
Julia di solito cerca di usare valori predefiniti, ma può farlo solo se ha abbastanza informazioni per inferire il tipo del campo.undef può essere un approccio flessibile ed efficiente.
Questo è stato usato, per esempio, nelle soluzioni della community per l'esercizio Circular Buffer (una tecnica avanzata, ma classificata come esercizio difficile).Ottenere un risultato undef da un tentativo di accedere a un valore è uno stato di errore, tipicamente segnalato con un UndefRefError.