Muitas linguagens têm uma forma como null ou none para indicar um valor inexistente.
Como Julia foi concebida para lidar com grandes volumes de dados (muitas vezes desorganizados), tem várias formas de inexistência.
O objetivo geral é sinalizar valores em falta ou suspeitos à medida que são encontrados, e depois continuar sem lançar uma exceção.
nothingSe um valor realmente não existe, é representado por nothing. Isto é provavelmente o mais próximo do que C (NULL) ou Python (None) fariam.
julia> n = nothing
julia> isnothing(n)
true
julia> typeof(n)
Nothing
Assim, nothing é um valor singular do tipo Nothing, e podemos testá-lo.
Um uso comum de nothing é como um valor de retorno (ou não-valor) para funções que são usadas apenas pelos seus efeitos secundários (impressão, configuração de rede, ou outra coisa qualquer).
missingPara situações em que um valor existe em teoria, mas não sabemos qual é, usa-se missing. Por exemplo, ao contar veículos que viajam numa estrada, os observadores humanos podem precisar de uma pausa ou os sensores automáticos podem avariar, mas o trânsito continua a fluir.
Assim, missing é um marcador de posição, alertando os humanos de que precisam de tomar uma decisão sobre como lidar com esta lacuna nos dados.
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
Poucas outras linguagens têm esta funcionalidade incorporada, mas equivalentes próximos são NA em R ou NULL em SQL.
O tipo de vetor no exemplo acima é definido como Union{Missing, Int64}, que tem alguma semelhança com tipos como Option ou Maybe noutras linguagens.
As expressões normalmente devolvem missing por predefinição se estiverem presentes valores missing.
Se quiseres que estes valores sejam ignorados, usa a função skipmissing() para tornar isto explícito:
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
Como skipmissing cria um iterador, envolve-o em collect() se precisares de um vetor.
Por vezes, é útil substituir valores missing por um valor predefinido.
A macro @coalesce() é útil para isto, pois devolve o primeiro valor não-missing (ou missing se não houver mais nada).
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"
"-"
NaNAbreviatura de "Not a Number", NaN sinaliza um problema de cálculo em situações em que se esperava um número.
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
Qualquer tipo de cálculo sobre dados que incluam um NaN dará um resultado NaN.
Atualmente, não existe uma função especial para remover valores NaN, mas a função padrão filter() pode fazer isto de forma bastante simples.
Apenas os valores para os quais uma determinada condição seja true serão copiados para o array resultante:
julia> filter(!isnan, [1, 2, NaN])
2-element Vector{Float64}:
1.0
2.0
Isto é algo que provavelmente vais usar com menos frequência. As exceções incluem:
struct) com campos não inicializados.
Julia normalmente tenta usar valores predefinidos, mas só o pode fazer se tiver informação suficiente para inferir o tipo do campo.undef pode ser uma abordagem flexível e eficiente.
Isto tem sido usado, por exemplo, em soluções da comunidade para o exercício Buffer Circular (uma técnica avançada, mas este é classificado como um exercício difícil).Obter um resultado undef de uma tentativa de aceder a um valor é um estado de erro, tipicamente sinalizado com um UndefRefError.