Переопределение equals, hashCode и toString в типе Clojure - PullRequest
10 голосов
/ 11 июня 2010

Я пытаюсь создать новый тип в Clojure, используя deftype для реализации двумерной (x, y) координаты, которая реализует протокол "Location".

Я также хотел бы иметь этореализовать стандартные методы Java equals, hashCode и toString.

Моя первоначальная попытка:

 (defprotocol Location   
   (get-x [p])  
   (get-y [p])   
   (add [p q]))


 (deftype Point [#^Integer x #^Integer y]   
     Location
       (get-x [p] x)
       (get-y [p] y) 
       (add [p q] 
         (let [x2 (get-x q)
               y2 (get-y q)]
           (Point. (+ x x2) (+ y y2))))   
     Object
       (toString [self] (str "(" x "," y ")"))
       (hashCode [self] (unchecked-add x (Integer/rotateRight y 16)))
       (equals [self b] 
         (and 
           (XXXinstanceofXXX Location b) 
           (= x (get-x b)) 
           (= y (get-y b)))))

Однако метод equals все еще нуждается в некотором способе разработки, если параметр b реализует протокол Location.

Каков правильный подход?Я на правильном пути?

1 Ответ

7 голосов
/ 11 июня 2010

Чтобы проверить, удовлетворяет ли протокол протоколу, есть satisfies?.

Редактировать:

Протоколы и типы данных являются слишком новыми в Clojure (и продолжают быстро развиваться)для меня, чтобы отметить много о том, что идиоматично или нет.Но вы должны заметить, что defrecord уже реализует равенство на основе типа и значения.Если вам действительно не нужен собственный хэш-код для ваших объектов, вы можете рассмотреть возможность использования defrecord.

(defrecord Point [#^Integer x #^Integer y]   
  Location
  (get-x [p] x)
  (get-y [p] y) 
  (add [p q] 
       (let [x2 (get-x q)
             y2 (get-y q)]
         (Point. (+ x x2) (+ y y2)))))

user> (= (Point. 1 2) {:x 1 :y 2})
false
user> (= (Point. 1 2) (Point. 1 2))
true

. Вы также получите дополнительный бонус за возможность доступа к вашим полям с помощью поиска по ключевым словам и возможность поставитьметаданные о ваших объектах, которые defrecord предоставляет вам бесплатно.

user> (:x (Point. 1 2))
1

Возможно, что defrecord -определенные вещи когда-нибудь будут иметь собственный синтаксис читателя в Clojure, так что они могут быть напечатаны для чтения и чтенияв с читателем Clojure.Если вы действительно не привязаны к своей версии toString, вы также можете об этом помнить.Прямо сейчас записи уже печатаются для человека, если не для машинного восприятия.

user> (Point. 1 2)
#:user.Point{:x 1, :y 2}
...