Ruby에는 변수가 정의되어 있는지 확인할 수 있는 defined? 키워드가 있습니다.
변수가 존재하면 해당 변수의 타입을 반환합니다:
apple = 1 defined?(apple) # "local-variable"
존재하지 않으면 nil을 반환합니다:
defined?(bacon) # nil
이는 JavaScript의 typeof 연산자와 비슷한 역할을 합니다. 만약 객체의 클래스를 알고 싶다면 defined? 대신 class 메서드를 사용하는 것이 좋습니다.
defined?에 대해 기억해 둘 만한 흥미로운 특징들이 있습니다:
defined?는 메서드가 아닌 키워드(keyword)입니다defined?는 이름 끝에 물음표(?)가 붙지만, Ruby의 일반적인 관례와 달리true나false를 반환하지 않는 몇 안 되는 요소 중 하나입니다defined?는 값이nil인 변수와 한 번도 설정된 적 없는 변수를 구분할 수 있습니다
이러한 특별한 속성들 때문에 이 키워드를 제대로 배워둘 가치가 충분합니다.
정의된 변수를 확인하는 더 나은 방법
defined? 키워드는 유용하지만 몇 가지 문제점이 있습니다.
왜 그럴까요?
연산자 우선순위(operator precedence)가 낮기 때문입니다.
예를 들어 다음과 같은 코드를 작성하면:
defined? orange && orange.size
결과는 "expression"이 됩니다.
orange && orange.size 전체가 defined?의 인자로 해석되기 때문입니다.
올바른 작성 방법은 다음과 같습니다:
defined?(orange) && orange.size
Ruby에는 변수가 정의되었는지 확인할 수 있는 다른 방법들도 있습니다.
지역 변수(local variable)의 경우:
local_variables.include?(:orange)
인스턴스 변수(instance variable)의 경우:
instance_variable_defined?("@food")
하지만 사실 이런 방법들은 사용할 필요가 거의 없습니다.
99%의 경우, 지역 변수가 존재하지 않는다면 오타가 있거나 누군가 변수 선언을 잊어버린 것입니다.
그렇다면 인스턴스 변수는 어떨까요?
정의되지 않은 인스턴스 변수는 항상 nil을 반환하므로, nil 여부를 확인하는 것이 좋습니다.
이럴 때 "안전 내비게이션 연산자(safe navigation operator)"(Ruby 2.3+)를 활용해 보세요. 이 연산자는 변수가 nil이 아닐 때만 메서드를 호출합니다.
예시는 다음과 같습니다:
if @user&.country == "Spain" # ... end
이 코드는 아래와 동일하게 동작합니다:
if @user && @user.country == "Spain" # ... end
이 방법들은 defined? 키워드만큼 범용적이지는 않지만, 더 예측 가능하고 오류 발생 가능성이 낮다는 장점이 있습니다.
메서드가 정의되어 있는지 확인하기
defined?를 사용해 메서드의 정의 여부를 확인할 수도 있지만, 실용성은 떨어집니다.
예시:
defined?(puts) # "method"
defined?는 메서드가 아닌 키워드이기 때문에 객체와 함께 사용할 수 없습니다.
즉, 다음과 같은 코드는 에러를 발생시킵니다:
[].defined?(:size) # undefined method `defined?' for []:Array
메서드 존재 여부를 확인하려면 respond_to? 메서드를 사용해야 합니다.
사용 방법은 다음과 같습니다:
[].respond_to?(:size) # true [].respond_to?(:orange) # false
클래스가 존재하는지 확인하기
예시:
defined?(Object) # "constant" defined?(A) # nil
클래스(상수)의 존재 여부를 확인할 때는 const_defined? 메서드를 사용하는 것이 더 좋습니다.
다음과 같이 사용합니다:
Object.const_defined?(:String) # true Object.const_defined?(:A) # false
정리
지금까지 특정 변수, 클래스 또는 메서드가 존재하는지 확인하는 쉬운 방법들을 살펴보았습니다!
변수를 다룰 때 대부분의 상황에서 실제로 필요한 것은 변수가 정의되었는지 여부가 아니라 nil인지 확인하는 것입니다. 아니면 더 나아가, 변환 메서드를 사용해 변수를 특정 클래스로 변환하는 것도 좋은 접근입니다.
이 글이 도움이 되셨기를 바랍니다! 유용했다면 공유해 주셔서 더 많은 사람들이 볼 수 있게 해주세요.