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

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

by
编辑 by
似乎有一个奇怪的边缘情况未在文档中(明确)说明:如果协议直接实现,但没有提供直接实现,元数据实现不会获胜。

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

然而,如果元数据实现缺失,则默认到扩展实现。文档的当前表述似乎并没有明确说明这种差异(但显然这些都是为了保留快速路径)。
...