Na

Nada em Julia

1 exercício

Sobre Nada

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.

nothing

Se 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).

missing

Para 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"
 "-"

NaN

Abreviaçã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

Dados indefinidos

Isso é algo que você provavelmente vai usar com menos frequência. As exceções incluem:

  • Há formas de criar tipos compostos (como 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.
  • Em alguns casos, inicializar um vetor como 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.

Editar via GitHub O link abre em uma nova janela ou aba

Aprenda Nada