7

我想扩展一个 Clojure 协议来处理 Java 原始数组。

(defprotocol PVectorisable
  (to-vector [a]))

(extend-protocol PVectorisable
  ??????
    (to-vector [coll]
      (Vectorz/create ^doubles coll))
  java.util.List
    ... other implementations......)

这可能吗,如果可以,上面的扩展协议定义中需要做什么(代替“??????”)?

4

2 回答 2

12

最简单的解决方案可能是通过反射以编程方式获取类。

(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 的数组有一些奇怪的名字。例如,浮点数组是[F. 如果你尝试直接在 REPL 中使用它,它会阻塞在 unmatched 上[。但是,您仍然可以将此名称与例如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")))

本文更详细地介绍了数组类。

于 2012-12-18T02:01:55.360 回答
2

正如 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))
于 2015-01-13T03:11:22.243 回答