我正在尝试使用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)))))但是,equals方法仍然需要一些方法来确定b参数是否实现了Location协议。
什么是正确的方法?我在正确的轨道上吗?
发布于 2010-06-11 05:23:21
要测试某些东西是否满足协议,可以使用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-defined中的东西可能会有自定义的阅读器语法,这样它们就可以用Clojure阅读器以可读的方式打印出来并读回。除非您真的依赖于您的toString版本,否则您可能也要牢记这一点。现在,记录已经打印出来,即使不是机器可读的,也是人类可读的。
user> (Point. 1 2)
#:user.Point{:x 1, :y 2}https://stackoverflow.com/questions/3018372
复制相似问题