繁体   English   中英

clojure的defrecord方法名称解析如何工作?

[英]How does clojure's defrecord method name resolution work?

在定义记录及其实现的接口之后,我可以通过其名称或使用点运算符的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]而不需要任何nameclash因为它们是命名空间(与Java相反,其中单个类不能用同名方法实现两个接口) 。

从用户的角度来看,协议方法与普通的非多态函数没有区别。

您可以使用interop调用协议方法的事实是一个实现细节。 原因是对于每个协议,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 ...)一样快。

要回复“可以导入java方法”,可以将它们包装在常规的fns中:

(def callme #(.callme %1 %2 %3))

(显然,您可能需要添加其他arities来解决重载并输入提示以删除反射)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM