在extend-protocol上使用第二个参数有什么用处

时间:2014-02-20 17:13:47

标签: clojure

extend-protocol上的第三个参数有什么用?假设我有

(defprotocol my-protocol 
  (foo [x]))

(extend-protocol my-protocol
  java.lang.String ; this
    (foo [x] (.length x)))

(foo "fooooo") ; 6

转换为:

(defprotocol my-protocol 
  (foo [x]))

(extend-protocol my-protocol
  java.lang.Long ; this
    (foo [x] (.length x)))

(foo "fooooo") ; it gave an output 6, while I expect it will throws, since I'm extending from Long, where it doesn't have length()
               ; In the end, it will just check on the args ? (in this case it's x)

我给了它java.lang.String,如果我将其更改为java.lang.Long,则foo上的调用不会抛出任何异常,而Long没有length() }} 在上面。它抛出的唯一情况是foo的参数没有length()

1 个答案:

答案 0 :(得分:2)

如果您将String更改为Long,那么在使用long调用foo时会出现异常:

;; calling foo with a Long:
user=> (foo 1)
IllegalArgumentException No matching field found: length for class java.lang.Long  clojure.lang.Reflector.getInstanceField (Reflector.java:271)

如果您未将协议扩展到String,则无法在字符串上调用foo

;; calling foo with a String with no implementation provided:
user=> (foo "asdf")
IllegalArgumentException No implementation of method: :foo of protocol: #'user/my-protocol found for class: java.lang.String  clojure.core/-cache-protocol-fn (core_deftype.clj:537)

当然,如果您先将my-protocol延伸至String,然后以单独的extend-protocol形式将其再次延伸至Long,则foo将用字符串做得很好。

Clojure不会尝试静态地确定(.length x)是否有意义,因为您扩展协议的类型也是如此。我想在这种情况下它可以,因为String是一个最终类,但不是一般情况下(非最终类/接口) - 或者至少不会改变它的动态语义。