clojure';defsrecord方法名称解析工作?

clojure';defsrecord方法名称解析工作?,clojure,protocols,Clojure,Protocols,在定义了一个记录及其实现的接口之后,我可以通过它的名称或使用java互操作方式使用点运算符调用它的方法 user=> (defprotocol Eat (eat [this])) Eat user=> (defrecord animal [name] Eat (eat [this] "eating")) user.animal user=> (eat (animal. "bob")) "eating" user=> (.eat (animal. "bob")

在定义了一个记录及其实现的接口之后,我可以通过它的名称或使用java互操作方式使用点运算符调用它的方法

 user=> (defprotocol Eat (eat [this]))
 Eat
 user=> (defrecord animal [name] Eat (eat [this] "eating"))
 user.animal
 user=> (eat (animal. "bob"))
 "eating"
 user=> (.eat (animal. "bob"))
 "eating"
 user=> 
在表面之下,那里发生了什么?是否定义了新的clojure函数?当您定义的函数共享相同的名称时会发生什么情况(可能吗?),如何解决这些歧义


另外,是否可以为其他java对象“导入”java方法,以便您不需要。运算符,这样的行为就像上面所说的?(例如,为了统一用户界面)

定义协议时,其每个方法都作为当前名称空间中的函数创建。因此,不能让两个协议在同一名称空间中定义同一个函数。这还意味着您可以将它们放在单独的名称空间中,并且给定的类型可以扩展它们[1],而不会产生任何名称冲突,因为它们是名称空间的(与Java相反,Java中的单个类不能实现两个同名方法的接口)

从用户的角度来看,协议方法与普通的非多态函数没有什么不同

您可以使用互操作调用协议方法,这是一个实现细节。原因是,对于每个协议,Clojure编译器都会创建一个相应的支持接口。稍后,当您使用内联协议扩展定义新类型时,该类型将实现这些协议的支持接口

因此,您不能对未提供内联扩展的对象使用互操作窗体:

(defrecord VacuumCleaner [brand model]
(extend-protocol Eat
  VacuumCleaner
  (eat [this] "eating legos and socks"))

(.eat (VaacumCleaner. "Dyson" "DC-20"))
; method not found exception
编译器对协议函数有特殊支持,因此它们被编译为实例检查,然后是虚拟方法调用,因此在适用时
(eat…
)将与
(.eat…
)一样快

要回答“can one import java methods”,您可以将它们封装在常规FN中:

(def callme #(.callme %1 %2 %3))
(显然,您可能需要添加其他算术以解释重载,并键入提示以删除反射)


[1] 但是,您不能扩展这两种内联形式(至少其中一种必须是
extend-*
形式),因为实现限制

我的风格偏好是避免记录(构造函数)和协议(调用)都使用Java互操作形式。在这种情况下:(吃(->动物“bob”))