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

这实际上并不影响方法的缓存,只是影响缓存的方法选择。

von
geändert von
似乎有一个奇怪的特殊情况,文档(明确地)没有涵盖:协议直接实现时,元数据实现并没有获胜,但并没有提供直接的实现。

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()'。

另一方面,如果元数据实现缺失,它会默认到扩展实现。当前文档的措辞似乎没有使这种差异明显(但显然都是为了保持快速路径)。
...