Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

루비 nil 완벽 가이드: 반드시 알아야 할 모든 것

Nil…

대체 무엇일까요?

nil은 루비(Ruby)에서 "빈 값" 또는 "기본값"을 나타내는 특별한 객체입니다. 또한 false처럼 동작하는 "falsy(거짓 같은)" 값이기 때문에, 조건문에서 사용하면 거짓으로 평가됩니다.

중요한 점:

nil 객체는 루비 전체에서 단 하나만 존재하며, object_id4입니다(64비트 루비에서는 8). 이것이 nil이 특별하게 취급되는 이유 중 하나입니다.

nil.object_id
# 4

이제 더 깊이 들여다보겠습니다!

Nil 값은 어디에서 오는 걸까?

많은 메서드가 결과로 nil을 반환할 수 있습니다.

이는 값을 요청했지만 그 값이 존재하지 않을 때 발생합니다.

예시:

  • 상품을 찾지 못한 경우
  • 배열 인덱스가 범위를 벗어난 경우
  • 해시(Hash)에 해당 키가 존재하지 않는 경우

이를 보여주는 코드입니다:

arr = [1,2,3]

arr[5]
# nil

우리는 호출한 메서드가 유효한 값을 반환하기를 기대하는데 nil이 반환되면 다양한 문제가 발생할 수 있습니다.

예를 들어 다음과 같은 NoMethodError 예외가 그렇습니다:

arr[5].size

# NoMethodError: undefined method 'size' for nil:NilClass

이런 오류를 피하려면 메서드를 호출하기 전에 값이 nil인지 먼저 확인해야 합니다.

루비에서 Nil 검사하기

"undefined method for nil:NilClass" 오류를 만나고 싶지 않다면 아래 방법들을 활용해 보세요.

nil이 아닐 때만 메서드 호출하기:

if array[5] && array[5].size
  # do something...
end

바로 이런 불편함 때문에 루비 2.3에서는 "안전 탐색(safe navigator)" 연산자(&.)가 도입되었습니다.

예시:

if arr[5]&.size
  # do something...
end

nil을 검사하는 또 다른 방법은 nil? 메서드를 사용하는 것입니다:

if @bacon.nil?
  # ...
end

또한 blank? 메서드를 사용할 수도 있습니다(레일즈에서만 제공).

다루는 객체에 따라서는 nil 검사 자체를 완전히 피할 수 있는 몇 가지 기법도 있습니다.

예를 들어 Hash와 Array 객체에는 fetch 메서드를 사용할 수 있습니다.

또는 직접 작성한 클래스에서 nil 대신 기본값을 반환하고 싶다면 "Null Object 패턴"을 활용할 수 있습니다.

Nil이 숨어 있는 다른 곳들

정의되지 않은 인스턴스 변수는 nil을 반환한다는 점을 기억해야 합니다.

@foo

# nil

인스턴스 변수 이름을 잘못 입력했거나 초기화를 잊었을 때 이런 상황이 발생할 수 있으니 주의하세요!

nil을 발견할 수 있는 또 다른 곳은 putsprint 메서드입니다.

이 두 메서드는 항상 nil을 반환합니다.

이 내용을 언급하는 이유는, 실제로 학생들이 다음과 같은 코드를 작성하는 것을 여러 번 보았기 때문입니다:

numbers = [1,2,3].map { |n| puts n * 2 }

그 결과 numbers[nil, nil, nil]이 됩니다. 이 경우 해결책은 간단히 블록 안에서 puts를 제거하는 것입니다.

NilClass 이해하기

다른 모든 루비 객체와 마찬가지로 nil도 고유한 메서드 집합을 가지고 있습니다.

Rubinius 소스 코드의 클래스 정의는 다음과 같습니다:

class NilClass
  def to_s
    ""
  end

  def inspect
    "nil"
  end

  def nil?
    true
  end

  def to_a
    []
  end

  def to_f
    0.0
  end

  def to_i
    0
  end

  def to_c
    Complex(0)
  end

  def to_h
    {}
  end
end

모든 to_something 계열 메서드가 빈 값(숫자의 경우 0)을 반환한다는 점에 주목하세요.

빈 해시, 빈 문자열, 빈 배열…

그 이유는 nil이 "아무것도 없음"을 나타내기 위해서입니다.

Null Object 패턴

nil에 대한 이야기에서 Null Object 패턴을 빼놓을 수 없습니다.

Sandi Metz는 훌륭한 강연 "Nothing is Something"에서, nil이 "아무것도 없음"을 의미하지만 더 구체적인 의미를 가질 수 있다고 지적합니다.

예를 들어, 상품을 찾는 메서드를 작성하면서 상품이 없을 때 기본 상품을 반환하고 싶다고 가정해 보겠습니다.

이럴 때 다음과 같은 null 상품을 반환할 수 있습니다:

class MissingProduct
  def name
    "Product not found"
  end
end

이제 실제 상품 객체와 null 상품이 섞인 배열이 있더라도, 모든 상품은 name 메서드를 가지게 됩니다. 따라서 NoMethodError 예외가 발생하지 않습니다.

: 객체의 타입을 확인하지 않고도 모든 객체를 동일한 방식으로 다룰 수 있다면, 그것이 바로 다형성(Polymorphism)을 활용하는 것입니다.

이런 종류의 객체는 프레젠테이션 레이어(뷰)에서는 매우 유용하지만, 컨트롤러에서는 상황이 다릅니다. 컨트롤러에서는 원하는 데이터가 없을 때 경고 메시지 표시나 리디렉션 등 다른 동작을 수행해야 하기 때문입니다.

Truthiness(참/거짓 판정)

nil에 대해 알아야 할 또 하나의 사실은, false(역시 객체입니다)와 함께 오직 이 두 값만이 "falsy"로 평가된다는 점입니다.

루비에서 그 외의 모든 값은 불리언 문맥에서 true로 간주됩니다.

일부 언어에서는 숫자 0false로 취급하지만, 루비에서는 그렇지 않습니다:

if 0
  puts 123
end

# 123

이 코드는 "만약 0이 참이라면 123을 출력하라"는 의미이며, 실제로 123이 출력됩니다.

요약

이 글에서 nil은 "아무것도 없음"을 나타내는 하나의 루비 객체라는 것을 배웠습니다.

또한 nilfalse만이 루비에서 "falsy"한 두 가지 값이며, 그 외의 모든 것은 "truthy"하다는 것도 배웠습니다.

이 글이 도움이 되었다면 좋아하는 소셜 네트워크에 공유하는 것을 잊지 마세요!