在Clojure deftype中覆盖equals,hashCode和toString

mik*_*era 10 protocols equals clojure deftype

我正在尝试使用deftype在Clojure中创建一个新类型来实现一个二维(x,y)坐标,它实现了一个"位置"协议.

我还想让它实现标准的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)))))
Run Code Online (Sandbox Code Playgroud)

但是,如果b参数实现了Location协议,则equals方法仍需要一些方法.

什么是正确的方法?我是在正确的轨道上吗?

Bri*_*per 7

为了测试某些东西是否满足协议,有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
Run Code Online (Sandbox Code Playgroud)

您还可以获得额外的好处,即能够通过关键字查找访问您的字段,并能够在您的对象上放置元数据,这样defrecord您就可以免费获得.

user> (:x (Point. 1 2))
1
Run Code Online (Sandbox Code Playgroud)

defrecord有一天,定义的东西可能会在Clojure中有自定义的阅读器语法,因此它们可以被可读地打印并用Clojure阅读器读回来.除非你真的喜欢你的版本,否则你也toString可以记住这一点.现在,如果不是机器可读的,记录已经打印出人类可读的.

user> (Point. 1 2)
#:user.Point{:x 1, :y 2}
Run Code Online (Sandbox Code Playgroud)

  • 如果您还没有,请阅读http://clojure.org/datatypes上的"为什么同时使用deftype和defrecord?*"部分.`deftype`似乎适用于实现Clojure本身的一些内容,或实现自己的新抽象数据类型.`defrecord`似乎是指"数据",即你的积分,或其他意味着在高水平消耗的数据.如果您可以使用哈希映射轻松替换您的类型,在您认为可以的情况下,那么可能是`defrecord`就是您想要的.只是我读了它. (3认同)