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

欢迎!请查阅关于页面,了解更多有关如何使用本站的信息。

0 投票
Spec
重新标记

嗨,自从推出以来,我们的代码库已经采用了extend-with-metadata协议,我们更喜欢映射组件而不是记录。

然而,我们的代码库和团队广泛使用了Clojure规范,并且我们原本期待以下形式的最后一个表达式会抛出错误:

(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 投票

我认为您应该像这样持有var,

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

或者使用包装函数进行另一种间接操作。否则,对var def-impl的检测将无效,因为您创建impl时,var已经被解引用。

谢谢 @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 的根并没有对 map f 产生影响,因为 map 已经不再包含对 var 的引用。
...