許多語言都有像是 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
很少有其他語言內建這項功能,但很接近的類似物是 R 的 NA 或 SQL 的 NULL。
上面範例中的向量型別被設為 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 建立的是疊代器,如果你需要向量,請用 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"
"-"
NaNNaN 是「Not a Number」的縮寫,用來標示在預期會出現數字的情況下所發生的計算問題。
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 可能是既靈活又高效能的作法。
舉例來說,社群對 環形緩衝區 練習的解答就用了這個技巧(這是進階技巧,不過這道練習的難度被評為困難)。嘗試存取某個值時得到 undef 結果,屬於錯誤狀態,通常會以 UndefRefError 標示。