if var
if
의 조건이 변수라면, then
분기 안에서 그 변수는 Nil
타입을 갖지 않는 것으로 취급됩니다.
a = some_condition ? nil : 3
# a는 Int32 혹은 Nil
if a
# a가 참이어야 하기 때문에
# a는 nil일 수 없으므로
# 이때 a는 Int32
a.abs
end
if
의 조건문에서 변수가 할당될 때에도 적용됩니다.
if a = some_expression
# a는 nil이 아님
end
조건에 &&
가 있을 때에도 똑같이 적용됩니다.
if a && b
# a와 b는 모두 nil이 아님
end
이때 &&
표현식의 우측에서도 a
가 Nil
이 아니라는 것이 보장됩니다.
물론 then
분기 안에서 변수를 다시 할당한다면 그 변수는 할당된 표현식에 따라 새로운 타입을 갖게 됩니다.
하지만 이는 인스턴스 변수나 클래스 변수에는 적용되지 않습니다.
if @a
# 이때 @a는 nil일 수 있음
end
이는 어떠한 메서드 호출이라도 잠재적으로 해당 변수를 건드릴 수 있기 때문입니다. 뿐만 아니라 조건을 확인한 다음 다른 스레드가 그 인스턴스 변수를 바꿀 수도 있습니다.
@a
를 nil
이 아닐 때에만 이용하려면 두 가지 방법이 있습니다.
# 첫 번째: 변수에 할당
if a = @a
# a는 nil이 아님
end
# 두 번째: 표준 라이브러리의 `Object#try`를 이용
@a.try do |a|
# a는 nil이 아님
end
게터나 속성 등 프록이나 메서드를 호출할 때에도 마찬가지입니다. nil이 될 수 있는 (혹은 공용체 타입인) 프록과 메서드는 두 번 이상 연속으로 호출했을 때 같은 값을 반환한다는 보장이 없기 때문입니다.
if method # 첫 호출은 Int32 혹은 Nil을 반환
# 첫 호출은 Nil을 반환하지 않았음
method # 그러나 두 번째 호출은 Int32 혹은 Nil을 반환
end
위에서 본, 인스턴스 변수를 다루는 기법을 프록 및 메서드 호출에 적용할 수 있습니다.