if var.nil?
if var.nil?
값이 nil인지 아닌지에 따라 분기해야 할 때가 많죠. if var.nil?는 그런 상황에서 컴파일러가 변수의 타입을 정확히 좁혀주는 기능이에요.
출처: Crystal 공식 문서
본문
if의 조건이 var.nil?이면, 컴파일러는 then 분기에서 var의 타입을 Nil로, else 분기에서 non-Nil로 알 수 있어요.
a = some_condition ? nil : 3
if a.nil?
# here a is Nil
else
# here a is Int32
end
인스턴스 변수
if var.nil?를 통한 타입 제한은 지역 변수(local variable)에만 적용돼요. 위 예시와 비슷한 코드에서 인스턴스 변수의 타입은 여전히 nilable이고, greet가 unless 분기에서 String을 기대하므로 컴파일 오류가 나요.
class Person
property name : String?
def greet
unless @name.nil?
puts "Hello, #{@name.upcase}" # Error: undefined method 'upcase' for Nil (compile-time type is (String | Nil))
else
puts "Hello"
end
end
end
Person.new.greet
이 문제는 값을 먼저 지역 변수에 저장하면 해결할 수 있어요.
def greet
name = @name
unless name.nil?
puts "Hello, #{name.upcase}" # name will be String - no compile error
else
puts "Hello"
end
end
이것은 Crystal의 멀티스레딩의 부산물이에요. Fiber가 존재하기 때문에, Crystal은 컴파일 시점에 if 분기에서 사용할 때 인스턴스 변수가 여전히 non-Nil인지 알 수 없어요.
더 알아보기
if var.nil?타입 제한은 지역 변수에만 적용된다는 점을 기억하세요. 인스턴스 변수는 먼저 지역 변수에 담아서 쓰는 게 일반적인 패턴이에요.- 관련 패턴으로 if var 문서도 참고할 수 있어요.