请分享您的想法,参加 2024 Clojure 状态调查!

欢迎!请参阅 关于 页面获取更多关于如何使用本网站的信息。

+1
协议

看起来元数据协议实现会覆盖 extend 调用,但不是直接实现。这是预期的吗?选择元数据协议是如何与 defprotocol 方法的缓存交互的?还有哪些陷阱需要注意?

Clojure 1.10 .3
user=> (defprotocol A :extend-via-metadata true (foo [this]))
A
user=> (defrecord Direct [] A (foo [_] :direct))
user.Direct
user=> (foo (->Direct))
:direct
user=> (foo (with-meta (->Direct) {`foo (fn [_] :meta)}))
:direct
user=> (defrecord Extend [])
user.Extend
user=> (extend-protocol A Extend (foo [_] :extend))
nil
user=> (foo (->Extend))
:extend
user=> (foo (with-meta (->Extend) {`foo (fn [_] :meta)}))
:meta

1 答案

+1

选定
 
最佳答案

是的,这是预期的。
https://clojure.org/reference/protocols#_extend_via_metadata

这并不会影响方法的缓存,只是影响选择要缓存的方法。


编辑
似乎存在一个奇特的边缘情况,这在文档中没有(明确)涉及:如果协议是直接实现的,但没有提供直接实现,则元数据实现不会获胜。

Clojure 1.10.3
user=> (defrecord MissingDirect [] A)
user.MissingDirect
user=> (foo (with-meta (->MissingDirect) {`foo (fn [_] :meta)}))
执行错误(AbstractMethodError)在 user/eval208 (REPL:1)。
接收器类 user.MissingDirect 没有定义或继承接口 user.A 中解析出的方法 'abstract java.lang.Object foo()' 的实现。

然而,如果元数据实现缺失,则默认为扩展实现。文档的当前措辞似乎并没有使这种差异明显(但显然这全部是为了保持快速路径)。
...