gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 09:20:51 27 4
gpt4 key购买 nike

定义记录及其实现的接口(interface)后,我可以通过其名称或使用点运算符使用 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 方法,这样您就不需要 .运算符(operator)的行为就像上面一样吗? (例如,为了统一用户界面)

最佳答案

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

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

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

因此,您无法在未内联提供扩展的对象上使用互操作表单:

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

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

编译器对协议(protocol)函数有特殊支持,因此它们被编译为实例检查,然后是虚拟方法调用,因此在适用时 (eat ...) 将与 一样快(.吃...).

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

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

(显然,您可能需要添加其他参数来考虑重载和类型提示以删除反射)

[1] 但是,由于实现限制,您不能同时扩展两者内联(至少其中一个必须采用 extend-* 形式)

关于clojure - Clojure 的 defrecord 方法名称解析如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4839013/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com