Muitas linguagens têm uma forma como null ou none de indicar um valor inexistente.
Como Julia foi projetada para lidar com grandes volumes de dados (muitas vezes bagunçados), ela tem várias formas de ausência de valor.
O objetivo geral é sinalizar valores ausentes ou suspeitos conforme eles forem encontrados, e depois continuar sem lançar uma exceção.
nothingSe um valor realmente não existe, ele é representado por nothing. Isso provavelmente é o mais próximo do que C (NULL) ou Python (None) fazem.
julia> n = nothing
julia> isnothing(n)
true
julia> typeof(n)
Nothing
Então nothing é um valor singleton do tipo Nothing, e podemos testar isso.
Um uso comum de nothing é como valor de retorno (ou não valor) de funções usadas apenas pelos seus efeitos colaterais (impressão, configuração de rede, ou qualquer outra coisa).
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 trafegam em uma estrada, os observadores humanos podem precisar de uma pausa ou os sensores automáticos podem falhar, mas o tráfego continua fluindo.
Assim, missing é um marcador de posição, avisando as pessoas que elas precisam decidir como lidar com essa 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 esse recurso embutido, mas os equivalentes mais próximos são NA no R ou NULL no SQL.
O tipo do vetor no exemplo acima é Union{Missing, Int64}, que tem alguma semelhança com tipos como Option ou Maybe em outras linguagens.
As expressões normalmente retornam missing por padrão se houver valores missing presentes.
Se você quer que esses valores sejam ignorados, use a função skipmissing() para deixar isso 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, envolva-o em collect() se você precisar de um vetor.
Às vezes é útil substituir valores missing por algum valor padrão.
A macro @coalesce() é útil para isso, pois retorna o primeiro valor que 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"
"-"
NaNAbreviação de "não é um número", 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 há uma função especial para remover valores NaN, mas a função padrão filter() consegue fazer isso de forma bem simples.
Só os valores para os quais uma condição dada é true serão copiados para o vetor resultante:
julia> filter(!isnan, [1, 2, NaN])
2-element Vector{Float64}:
1.0
2.0
Isso é algo que você provavelmente vai usar com menos frequência. As exceções incluem:
struct) com campos não inicializados.
Julia normalmente tenta usar valores padrão, mas só consegue fazer isso se tiver informações suficientes para inferir o tipo do campo.undef pode ser uma abordagem flexível e eficiente.
Isso tem sido usado, por exemplo, em soluções da comunidade para o exercício Circular Buffer (uma técnica avançada, mas o exercício é classificado como difícil).Obter um resultado undef ao tentar acessar um valor é um estado de erro, normalmente sinalizado com um UndefRefError.