객체 동등성과 해싱

객체 동등성과 해싱 (Object Equality and Hashing)

클래스 인스턴스가 equal?에 의해 어떻게 비교되는지 커스터마이즈하고 싶다면, equal<%> 인터페이스를 구현하면 돼요. 이 인터페이스는 구조체 타입의 prop:equal+hash와 유사하게, 동등성 비교와 해시 코드 계산을 위한 메서드들을 제공해요.

출처: Racket Reference

본문

기본적으로, 서로 다른 클래스의 인스턴스이거나 비투명(non-transparent) 클래스의 인스턴스인 객체들은 eq?일 때만 equal?이에요. 투명 구조체처럼, 같은 투명 클래스(즉 클래스의 모든 슈퍼클래스가 inspector로 #f를 가진 클래스)의 인스턴스인 두 객체는 필드 값이 equal?일 때 equal?이 돼요.

클래스 인스턴스가 equal?에 의해 다른 인스턴스와 비교되는 방식을 커스터마이즈하려면 equal<%> 인터페이스를 구현해요.

interface

equal<%> : interface?

equal<%> 인터페이스는 세 개의 메서드를 포함하며, 이들은 prop:equal+hash를 가진 구조체 타입에 제공되는 함수들과 유사해요:

  • equal-to? — 두 인자를 받아요. 첫 번째 인자는 대상 객체와 비교되는, 같은 클래스(또는 equal<%>의 구현을 다시 선언하지 않는 서브클래스)의 인스턴스인 객체예요. 두 번째 인자는 재귀 동등성 검사에 사용해야 하는, 두 인자를 받는 equal? 같은 프로시저예요. 객체와 메서드의 첫 번째 인자가 같으면 참 값을, 그렇지 않으면 #f를 돌려줘야 해요.

  • equal-hash-code-of — 재귀 해시 코드 계산에 사용해야 하는, 한 인자를 받는 프로시저를 인자로 받아요. 대상 객체의 해시 코드를 나타내는 정확한 정수를 돌려줘야 해요.

  • equal-secondary-hash-code-of — 재귀 해시 코드 계산에 사용해야 하는, 한 인자를 받는 프로시저를 인자로 받아요. 대상 객체의 이차 해시 코드를 나타내는 정확한 정수를 돌려줘야 해요.

equal<%> 인터페이스는 인터페이스의 구현을 선언하는 것과 인터페이스를 상속하는 것이 다르다는 점에서 특이해요. 두 객체는, 명시적으로 equal<%>를 구현하는 가장 구체적인 조상이 같은 클래스들의 인스턴스일 때만 equal할 수 있어요. 동등성 비교와 해시 코드에 대한 더 많은 정보는 prop:equal+hash를 참고하세요. equal<%> 인터페이스는 interface*prop:equal+hash로 구현돼요.

예시:

#lang racket

;; Case insensitive words:
(define ci-word%
  (class* object% (equal<%>)

    ;; Initialization
    (init-field word)
    (super-new)

    ;; We define equality to ignore case:
    (define/public (equal-to? other recur)
      (string-ci=? word (get-field word other)))

    ;; The hash codes need to be insensitive to casing as well.
    ;; We'll just downcase the word and get its hash code.
    (define/public (equal-hash-code-of hash-code)
      (hash-code (string-downcase word)))

    (define/public (equal-secondary-hash-code-of hash-code)
      (hash-code (string-downcase word)))))

;; We can create a hash with a single word:
(define h (make-hash))
(hash-set! h (new ci-word% [word "inconceivable!"]) 'value)

;; Lookup into the hash should be case-insensitive, so that
;; both of these should return 'value.
(hash-ref h (new ci-word% [word "inconceivable!"]))
(hash-ref h (new ci-word% [word "INCONCEIVABLE!"]))

;; Comparison fails if we use a non-ci-word%:
(hash-ref h "inconceivable!" 'i-dont-think-it-means-what-you-think-it-means)

더 알아보기