2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!请访问关于页面了解相关工作原理的更多信息。

0
图片不可见 Spec
重新标记

你好,我们的代码库自从引入 extend-with-metadata 协议以来就开始使用它 - 我们更喜欢映射组件而不是记录。

然而,代码库和团队都是 Clojure Spec 的大用户,我们原本预期以下语句.should 抛出异常:

(ns defproto-spec.test
  (:require [clojure.spec.alpha :as s]
            [clojure.spec.test.alpha :as st]))

(defprotocol SpecTest
  :extend-via-metadata true
  (delete [impl id]))

(s/fdef delete-impl
  :args (s/cat :impl any? :id string?))

(defn delete-impl [_ id]
  (println (str "This deletes " id))
  id)

(def impl (with-meta {} {`delete delete-impl}))

(st/instrument)

(delete impl 1) ;; should throw but it doesn't

为什么我们期待它能正常工作呢?

也许是因为这个特性较新(1.10)以及以下原因:

defproto-spec.test> (st/instrument)
[defproto-spec.test/delete-me defproto-spec.test/delete-impl]

不幸的是,情况并非如此。如果这一功能还没有在别人的流程中,我愿意修复这个问题并记录下来。

谢谢,
Andrea.

1 个答案

+2
图片不可见

我想你可能应该像这样保留变量:

(def impl (with-meta {} {`delete #'delete-impl}))

或者使用包装函数进行再次间接处理。否则,由于 def-impl 已经在创建 impl 时被解引用,因此对变量进行工具化不起作用。

感谢 @borkdude,让我试试 - 你在某个地方找到过这个吗?

编辑:成功了!

如果有必要,是否应该记录下来,如果需要,在哪里?
也许这有所帮助

```
user=> (def f (fn [] :foo))
#'user/f
user=> (def m {:f f})
#'user/m
user=> ((:f m))
:foo
user=> (alter-var-root #'f (constantly (fn [] :bar)))
#object[user$eval143$fn__144 0x31e72cbc "user$eval143$fn__144@31e72cbc"]
user=> ((:f m))
:foo
user=> (f)
:bar
```

如您所见,更改 var f 的根对映射 m 没有任何影响,因为映射不再包含对 var 的引用。
这是我已经忘记的一段魔法,但现在我明白为什么它会发生。但是——我认为这并不简单,而且值得记录下来。
...