我想扩展一个Clojure协议来处理Java原始数组。
(defprotocol PVectorisable
(to-vector [a]))
(extend-protocol PVectorisable
??????
(to-vector [coll]
(Vectorz/create ^doubles coll))
java.util.List
... other implementations......)
这是可能的,如果是这样,上面的扩展协议定义需要什么(代替“??????”)?
答案 0 :(得分:9)
最简单的解决方案可能是以反射方式编写类。
(defprotocol do-a-thing
(print-thing [thing]))
(extend-protocol do-a-thing
(class (float-array 0))
(print-thing [_]
(println "it's a float array")))
Java的数组有些奇怪的名字。例如,float数组是[F
。如果您尝试直接在REPL中使用它,它将会阻塞不匹配的[
。但是,您仍然可以使用此名称,例如Class/forName
。
(defprotocol do-another-thing
(print-another-thing [thing]))
(extend-protocol do-another-thing
(Class/forName "[F")
(print-another-thing [_]
(println "it's still a float array")))
This article详细介绍了数组类。
答案 1 :(得分:1)
正如hadronzoo所指出的,Class / forName解决方案只有在它是defprotocol的第一个定义时才有效,它将解决方案限制为每个协议只有一个数组类型(或者必须进行多个defprotocol定义)。这可以使用宏来处理多个数组类型,以避免读者无法解析数组符号的问题:
(defprotocol ISample
(sample [_]))
(defmacro extend-protocol-arrays []
(let [ba (symbol "[B")
ia (symbol "[I")
oa (symbol "[Ljava.lang.Object;")]
`(extend-protocol ISample
~ba
(sample [this#] (println "Byte Array"))
~ia
(sample [this#] (println "Int Array"))
~oa
(sample [this#] (println "Object Array")))))
(extend-protocol-arrays)
(sample (byte-array 0))
(sample (int-array 0))
(sample (make-array Object 0))