Clojure 什么';这是扩展协议上第二个参数的用法

Clojure 什么';这是扩展协议上第二个参数的用法,clojure,Clojure,扩展协议上的第三个参数有什么用途?如果我有 (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

扩展协议
上的第三个参数有什么用途?如果我有

(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
is的参数没有
length()

如果将
String
更改为
Long
,则调用
foo
时会出现异常,并使用Long:

;; 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
是一个最终类,但在一般情况下(非最终类/接口)——或者至少在不改变其动态语义的情况下不是这样。

我想OP想知道为什么
x
上似乎没有隐式类型标记,也就是说,尽管
Long
没有方法
length
,但为什么在编译时没有抛出异常。有什么想法吗?(哈,你在我打字的时候回答了。那就别管了。;):-
x
实际上是隐式地暗示了这里的类型(协议扩展到的类型),但是类型暗示只是用来避免反射。所以这只是为了抽象,对吗?我不太明白。如果您要求对
扩展协议
的类型参数进行最终澄清,他们会告诉Clojure要将协议扩展到哪种类型。静态地确定给定实现对哪些类型有意义是不可能的(如果只是因为可以随时动态创建新类型的话),即使有可能,程序员也可能不希望进行所有这些扩展。@MichałMarczyk我更新了我的问题,只是为了确保你明白我的意思。请看一看。正如我在回答中提到的,如果您将协议扩展到
String
,然后扩展到
Long
,那么
String
的实现不会消失。这就是为什么
foo
仍然可以处理字符串。但是现在您还有一个
Long
的实现,这是没有意义的,因此如果您使用Long调用
foo
,而不是告诉您没有匹配的实现,Clojure将尝试使用您提供的实现,并在执行时遇到问题。