我正在关注clojure.spec的指南(http://clojure.org/guides/spec)。我对序列规范alt
和or
之间的区别感到困惑。
对我来说,以下两个例子同样有效。那么这两者之间的区别是什么呢?
; Use `alt`
(s/def ::config (s/* (s/cat :prop string?
:val (s/alt :s string? :b boolean?))))
(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])
; Use `or`
(s/def ::config (s/* (s/cat :prop string?
:val (s/or :s string? :b boolean?))))
(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])
答案 0 :(得分:12)
s/alt
用于连接嵌套的正则表达式规范,其中使用s/or
指定嵌套序列。在您的示例中,由于您没有使用嵌套的正则表达式规范,因此它没有任何区别。这是一个例子:
(s/def ::number-regex (s/* number?))
(s/def ::or-example (s/cat :nums (s/or :numbers ::number-regex)))
(s/valid? ::or-example [1 2 3])
;;-> false
(s/valid? ::or-example [[1 2 3]])
;;-> true
如您所见,or
指定了一个嵌套序列,其中启动了一个新的正则表达式上下文,而alt
指定了相反的:
(s/def ::alt-example (s/cat :nums (s/alt :numbers ::number-regex)))
(s/valid? ::alt-example [1 2 3])
;;-> true
(s/valid? ::alt-example [[1 2 3]])
;;-> false
答案 1 :(得分:8)
来自http://clojure.org/guides/spec,我们知道
当组合正则表达式操作时,它们描述单个序列。
这意味着如果你想要有效嵌套序列,你应该这样做。
(s/def ::config (s/*
(s/cat :prop string?
:val (s/spec
(s/alt :s string? :b #(instance? Boolean %))))))
然后您的数据看起来像这样(注意括号左右)
(s/explain ::config ["-server" ["foo"] "-verbose" [true] "-user" [13]])
另外,如果你这样做(s /或)。
(s/def ::config (s/* (s/cat :prop string?
:val (s/spec
(s/or :s string? :b #(instance? Boolean %))))))
您的数据应与旧数据相同(注意周围没有括号)
(s/explain ::config ["-server" "foo" "-verbose" true "-user" 13])
BTW,对于非嵌套序列。 (s / alt)和(s /或)之间仍有一点点差异:
;;; for (s/or)
(s/def ::name-or-id (s/or :name string?
:id int?))
(s/conform ::name-or-id 42) ;;=> [:id 42]
;;; for (s/alt)
(s/def ::name-or-id (s/alt :name string?
:id int?))
(s/conform ::name-or-id [42]) ;;=> [:id 42]