if var
if var
변수가 if의 조건이면, then 분기 안에서 그 변수는 Nil 타입이 아닌 것으로 취급돼요. 이 논리는 if의 조건에서 변수를 할당할 때나 && 연산자가 있을 때도 적용되지만, 지역 변수에만 동작해요.
본문
변수 하나가 if의 조건이면, then 분기 안에서 그 변수는 Nil 타입이 아닌 것으로 간주돼요:
a = some_condition ? nil : 3
# a is Int32 or Nil
if a
# Since the only way to get here is if a is truthy,
# a can't be nil. So here a is Int32.
a.abs
end
이것은 if의 조건에서 변수를 할당할 때도 적용돼요:
if a = some_expression
# here a is not nil
end
이 논리는 조건에 && 연산자가 있을 때도 적용돼요:
if a && b
# here both a and b are guaranteed not to be Nil
end
여기서 && 표현식의 오른쪽에도 a가 Nil이 아님이 보장돼요.
물론 then 분기 안에서 변수를 다시 할당하면, 그 변수는 할당된 표현식에 기반한 새 타입을 갖게 돼요.
한계 (Limitations)
위 논리는 지역 변수에만 동작해요. 인스턴스 변수, 클래스 변수, 클로저 안에 묶인 변수에는 동작하지 않아요. 이런 변수들은 조건을 확인한 뒤 다른 파이버(fiber)에 의해 값이 바뀌어 nil이 될 수 있기 때문이에요. 상수(constant)에서도 동작하지 않아요.
if @a
# here `@a` can be nil
end
if @@a
# here `@@a` can be nil
end
a = nil
closure = -> { a = "foo" }
if a
# here `a` can be nil
end
이것은 값을 새 지역 변수에 할당하면 우회할 수 있어요:
if a = @a
# here `a` can't be nil
end
또 다른 방법은 표준 라이브러리의 Object#try를 쓰는 거예요. 이 메서드는 값이 nil이 아닐 때만 블록을 실행해요:
@a.try do |a|
# here `a` can't be nil
end
메서드 호출 (Method calls)
그 논리는 proc과 메서드 호출에도 동작하지 않아요. getter와 프로퍼티를 포함해요. nilable (더 일반적으로는 유니온 타입) proc과 메서드는 두 번 연속 호출했을 때 같은 더 구체적인 타입을 반환한다는 보장이 없기 때문이에요.
if method # first call to a method that can return Int32 or Nil
# here we know that the first call did not return Nil
method # second call can still return Int32 or Nil
end
인스턴스 변수에 대해 위에서 설명한 기법들은 proc과 메서드 호출에도 마찬가지로 동작해요.