3

我试图在 Clojure 1.4 中使用原始参数定义一个协议(这样我就可以避免在性能敏感代码中不必要的原始装箱):

(defprotocol A
  (foo [a ^long x]))

(extend-type java.lang.String A 
  (foo [s ^long x] (.charAt s x)))

这看起来工作正常,但当我尝试使用它时失败并出现异常:

(foo "abracadarbra" 3)
=> ClassCastException XXXX cannot be cast to clojure.lang.IFn$OLO

我究竟做错了什么?

4

2 回答 2

3

经过一些进一步的研究,协议似乎还不支持原始类型提示(从 Clojure 1.4 开始)。参见例如https://groups.google.com/d/topic/clojure-dev/HxBqIewc494/discussion

替代方案似乎是:

  • 编写带有原始提示的常规函数​​。你失去了多态性。
  • 使用 Java 接口(您可以使用reify在 Clojure 中构建实例)
于 2012-08-28T05:59:16.497 回答
2

从 中取出类型提示defprotocol并将其留在extend-type

(defprotocol A
(foo [a x]))

(extend-type java.lang.String A 
  (foo [s ^Long x] (.charAt s x)))
nil
core> (foo "abracadarbra" 3)
\a

或者您可以像这样更改类型提示:

(defprotocol A
(foo [a ^Long/TYPE x]))

(extend-type java.lang.String A 
  (foo [s ^long x] (.charAt s x)))
nil
core> (foo "abracadarbra" 3)
\a

如果没有提示,这仍然不会产生反射警告defprotocol

编辑:

(extend-type java.lang.String A 
  (foo [s ^Long x] (type x)))
nil
core> (foo "abracadarbra" 3)
java.lang.Long
于 2012-08-28T04:28:59.037 回答