许多语言都有null或none这样的方式来表示一个不存在的值。
由于 Julia 的设计目标是处理大量(往往很杂乱)的数据,它有多种表示nothingness的形式。
总体目标是,在遇到缺失或可疑的值时就把它标记出来,然后继续运行,而不是抛出异常。
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标记出来。