无值

无值 属于 Julia

1 个练习

关于 无值

许多语言都有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"
 "-"

NaN

NaN是“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标记出来。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 无值