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()
。
答案 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
是一个最终类,但不是一般情况下(非最终类/接口) - 或者至少不会改变它的动态语义。