많은 언어에는 존재하지 않는 값을 나타내는 null이나 none 같은 방법이 있어요.
Julia는 대량의 (종종 지저분한) 데이터를 다루도록 설계되었기 때문에, 여러 가지 형태의 없음을 제공해요.
전체적인 목표는 빠졌거나 의심스러운 값을 만나는 즉시 표시해 두고, 예외를 발생시키지 않고 계속 진행하는 거예요.
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"Not a Number"의 줄임말인 NaN은 숫자가 있어야 할 상황에서 계산에 문제가 생겼음을 표시해요.
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로 초기화하는 것이 유연하고 성능도 좋은 방법이 될 수 있어요.
예를 들어 Circular Buffer 연습 문제의 커뮤니티 풀이에서 이 기법이 쓰였어요(고급 기법이지만, 이 문제는 어려움 난이도로 분류돼요).값에 접근하려다 undef 결과를 얻는 것은 오류 상태이며, 보통 UndefRefError로 표시돼요.