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

Ruby에서 == 메서드로 객체 동등성 비교하고 직접 구현하는 방법

동등성(equality)이란 두 대상이 같다는 것을 의미합니다. Ruby에서는 객체와 그 값을 비교하여 두 객체가 같은지 판단할 수 있습니다.

그렇다면 질문은 이것입니다.

Ruby에서 두 객체는 어떻게 비교할까요?

답은 간단합니다.

1 == 1

# true

아마 이미 익숙하게 사용하고 계실 겁니다.

하지만 ==가 단순한 문법이 아니라 하나의 메서드라는 사실을 알고 계셨나요?

이것의 의미는 상당히 큽니다.

자신만의 클래스에서 이 메서드를 직접 구현하면 클래스를 훨씬 더 강력하게 만들 수 있습니다. 지금부터 그 방법을 자세히 알아보겠습니다!

두 객체가 '같다'는 것은 무엇을 의미할까?

문자열은 다음과 같이 비교할 수 있습니다.

"foo" == "foo"

단어와 문자가 모두 같다면 두 문자열은 동등하며, 표현식은 true를 반환합니다.

이것이 가능한 이유는 String 클래스가 문자열을 비교하는 방법을 아는 ==(등호 두 개) 메서드를 내부적으로 구현하고 있기 때문입니다.

그런데 만약 String 클래스에 == 메서드가 없다면 어떻게 될까요?

그 경우 Ruby는 Object 클래스의 == 구현을 사용하게 되는데, 이 기본 구현은 객체의 내용이 아니라 객체의 정체성(object identity), 즉 동일한 객체인지 여부를 검사합니다.

예시:

Object.new == Object.new # false
String.new == String.new # true

Objectfalse를 반환하는 이유는 새로 생성된 두 객체는 서로 다른 object id를 가지기 때문입니다.

반면 String은 내용을 기준으로 비교하기 때문에, 새로 생성된 두 빈 문자열은 내용이 같으므로(둘 다 비어 있음) true를 반환합니다.

동등성 직접 구현하기

이제 배운 내용을 활용해, 객체끼리 비교할 수 있는 강력한 나만의 클래스를 만들어 보겠습니다.

== 메서드를 덕분에...

여러분의 클래스 인스턴스 두 개가 '같다'는 것이 정확히 무엇을 의미하는지 직접 정의할 수 있습니다.

예시:

class Product
  attr_reader :name, :price

  def initialize(name, price)
    @name, @price = name, price
  end

  def ==(other)
    self.name  == other.name &&
    self.price == other.price
  end
end

p1 = Product.new('book', 49)
p2 = Product.new('book', 49)

p1 == p2 # true

위 코드의 == 메서드는 이름과 가격이 모두 같아야 두 Product 객체를 동등하다고 판단한다는 규칙을 정의합니다.

기억하세요:

이 메서드를 직접 구현하지 않으면(또는 제 책에서 설명하는 Comparable 모듈을 사용하지 않으면) 두 객체는 값이 아니라 object id를 기준으로 비교됩니다.

또 한 가지 참고할 점은, Struct를 사용하면 == 메서드가 이미 내장되어 있다는 것입니다.

삼중 등호(===)는 어떨까?

==가 메서드라면 ===도 메서드일까요? 답은 그렇습니다 🙂

그렇다면 둘의 차이점은 무엇일까요?

Javascript에서는 차이가 명확합니다. ==는 타입이 다를 경우(1 vs '1') 타입 변환을 시도하고, ===는 '엄격한(strict)' 동등성 검사를 수행합니다.

하지만 Ruby에는 그런 구분이 없습니다. ===의 의미는 이를 구현하는 클래스에 따라 달라집니다.

많은 경우 ===는 단순히 ==의 별칭(alias)입니다.

StringObject가 그 예입니다.

반면 ===에 특별한 의미를 부여하는 내장 클래스들은 다음과 같습니다:

클래스 의미
Range 객체가 해당 범위(range)에 포함되어 있으면 true, 아니면 false를 반환합니다.
Regexp 정규표현식을 문자열과 매칭합니다.
Module 객체가 해당 모듈 또는 그 하위 클래스의 인스턴스이면 true를 반환합니다.
Proc Proc#call처럼 객체를 인수로 블록을 실행합니다. case 문의 when 절에서 proc 객체를 대상으로 사용할 수 있도록 하기 위함입니다.

마무리

이 글에서는 == 메서드를 직접 구현하여 클래스를 더 강력하게 만드는 방법을 배웠고, =====의 차이점도 함께 살펴보았습니다.

더 많은 사람들이 볼 수 있도록 이 글을 공유하는 것도 잊지 마세요 🙂