使用带有原始参数的协议

时间:2012-08-28 03:58:36

标签: clojure protocols primitive

我正在尝试使用原始参数在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

我做错了什么?

2 个答案:

答案 0 :(得分:3)

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

替代品似乎是:

  • 使用原始提示编写常规函数。你失去了多态性。
  • 使用Java界面(您可以使用reify在Clojure中构建实例)

答案 1 :(得分: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