简体   繁体   English

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

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

After defining a record and the interfaces it implements, I can call its methods either by its name or using the java interop way using the dot operator. 在定义记录及其实现的接口之后,我可以通过其名称或使用点运算符的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=> 

Under the surface, what is going on there? 在表面下,那里发生了什么? Are there new clojure functions being defined? 是否定义了新的clojure函数? What happens when there are functions you defined that share the same name (is this possible?), how are these ambiguities resolved? 如果您定义的函数共享相同的名称会发生​​什么(这可能吗?),这些歧义如何解决?

Also, is it possible to "import" java methods for other java objects so that you do not need the . 此外,是否可以为其他java对象“导入”java方法,以便您不需要。 operator so that behavior is like above? 运营商,以便行为如上? (For the purpose, for example, of unifying the user interface) (例如,用于统一用户界面的目的)

When you define a protocol, each of its methods are created as functions in your current namespaces. 定义协议时,每个方法都在当前名称空间中创建为函数。 It follows that you can't have two protocols defining the same function in the same namespace. 因此,您不能在同一名称空间中使用两个协议来定义相同的功能。 It also means that you can have them in separate namespaces and that a given type can extend both[1] of them without any nameclash because they are namespaced (in opposition to Java where a single class can't implement two interfaces with homonymous methods). 它还意味着你可以将它们放在不同的命名空间中,并且给定的类型可以扩展它们[1]而不需要任何nameclash因为它们是命名空间(与Java相反,其中单个类不能用同名方法实现两个接口) 。

From a user perspective, protocol methods are no different from plain old non-polymorphic functions. 从用户的角度来看,协议方法与普通的非多态函数没有区别。

The fact that you can call a protocol method using interop is an implementation detail. 您可以使用interop调用协议方法的事实是一个实现细节。 The reason for that is that for each protocol, the Clojure compiler creates a corresponding backing interface. 原因是对于每个协议,Clojure编译器创建相应的后备接口。 Later on when you define a new type with inline protocol extensions, then this type will implement these protocols' backing interfaces. 稍后,当您定义具有内联协议扩展的新类型时,此类型将实现这些协议的后备接口。

Consequently you can't use the interop form on an object for which the extension hasn't been provided inline: 因此,您无法在未提供内联扩展的对象上使用互操作表单:

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

(.eat (VaacumCleaner. "Dyson" "DC-20"))
; method not found exception

The compiler has special support for protocol functions so they are compiled as an instance check followed by a virtual method call, so when applicable (eat ...) will be as fast as (.eat ...) . 编译器对协议函数有特殊支持,因此它们被编译为实例检查,后跟虚拟方法调用,因此适用时(eat ...)将与(.eat ...)一样快。

To reply to "can one import java methods", you can wrap them in regular fns: 要回复“可以导入java方法”,可以将它们包装在常规的fns中:

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

(obviously you may need to add other arities to account for overloads and type hints to remove reflection) (显然,您可能需要添加其他arities来解决重载并输入提示以删除反射)

[1] however you can't extend both inline (at least one of them must be in a extend-* form), because of an implementation limitation [1]但是你不能同时扩展内联 (至少其中一个必须是extend-*形式),因为实现限制

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

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