Я пытаюсь создать новый тип в Clojure с помощью deftype для реализации двумерного (x, y) координата, которая реализует протокол "Местоположения".
Я также хотел бы иметь эту реализацию, которой стандартный Java равняется, хэш-код и 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)))))
Однако равняется методу, все еще нуждается в некотором способе удаться, реализует ли b параметр протокол Местоположения.
Каков правильный подход? Я на правильном пути?
Чтобы проверить, удовлетворяет ли что-либо протоколу, существует удовлетворяет?
.
Протоколы и типы данных слишком новы в 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
-defined вещи когда-нибудь будут иметь собственный синтаксис читателя в Clojure, поэтому их можно будет распечатать и прочитать обратно с помощью читателя Clojure. Если вы действительно не привязаны к своей версии toString
, вы также можете иметь это в виду. Прямо сейчас записи уже печатаются для человека, если не для машинного чтения.
user> (Point. 1 2)
#:user.Point{:x 1, :y 2}