5

如果我定义了以下记录:

(defrecord Person [name id])

以及以下内容:

(s/def ::name string?)
(s/def ::id int?)
(s/def ::person (s/keys :req-un [::name ::id]))

如何确保您不能创建不符合 ::person 规范的 Person?换句话说,以下应该引发异常:

(->Person "Fred" "3")

我试过了:

(s/fdef ->Person :ret ::person)

但打电话:

(->Person "Fred" "3")

不会引发异常。

然而:

(s/conform ::person (->Person "Fred" "3"))

确实产生了预期:

:clojure.spec/invalid

谢谢

4

1 回答 1

11

fdef:ret 和 :fn 规范仅在测试期间clojure.spec.test/check检查,但您可以使用 fdef :args 规范在检测时检查构造函数的输入。

(s/fdef ->Person
  :args (s/cat :name ::name :id ::id)
  :ret ::person)

(require '[clojure.spec.test :as stest])
(stest/instrument `->Person)

(->Person "Fred" "3")

=> CompilerException clojure.lang.ExceptionInfo: Call to #'spec.examples.guide/->Person did not conform to spec:
In: [1] val: "3" fails spec: :spec.examples.guide/id at: [:args :id] predicate: int?
:clojure.spec/args  ("Fred" "3")
:clojure.spec/failure  :instrument
:clojure.spec.test/caller  {:file "guide.clj", :line 709, :var-scope spec.examples.guide/eval3771}

使用匹配的规范对构造函数的 defrecord 和 fdef 的组合进行宏化并不难。

于 2016-07-22T04:29:59.343 回答