为什么我的 or-spec 只对给定的规格之一有效?
Why is my or-spec only valid for one of the given specs?
考虑文本或 link 层端口号的以下规范:
(require '[clojure.spec.alpha :as spec])
(spec/def ::text (spec/and string? not-empty))
(spec/valid? ::text "a") ; => true
(spec/valid? ::text "") ; => false
(spec/def ::port (spec/and pos-int? (partial > 65535)))
(spec/valid? ::port 4) ; => true
(spec/valid? ::port 0) ; => false
(spec/def ::text-or-port (spec/or ::text ::port))
(spec/valid? ::text-or-port 5) ; => true
(spec/valid? ::text-or-port "hi") ; => false
出于某种原因,它只接受端口号而不接受文本,为什么会这样?
理解这个问题的关键可以在documentation和使用spec/conform
中找到。
(spec/conform ::text-or-port 5)
; => [:user/text 5]
问题是 clojure.spec.alpha/or
有一个 API 与 clojure.core/or
不同,它给出了两个参数 returns 第一个真实的:
(#(or (string? %) (integer? %)) 5) ; => true
(#(or (string? %) (integer? %)) "") ; => true
(#(or (string? %) (integer? %)) :a) ; => false
而是需要成对的标签和 specs/predicates。而且由于甚至命名空间关键字也被接受为标签,因此 OP 中给出的 ::text-or-port
规范仅匹配通过 ::port
要求并为其赋予标签 ::text
的规范。以下是我们要匹配的正确规范:
(spec/def ::text-or-port (spec/or :text ::text
:port ::port))
(spec/valid? ::text-or-port "hi") ; => true
(spec/valid? ::text-or-port 10) ; => true
考虑文本或 link 层端口号的以下规范:
(require '[clojure.spec.alpha :as spec])
(spec/def ::text (spec/and string? not-empty))
(spec/valid? ::text "a") ; => true
(spec/valid? ::text "") ; => false
(spec/def ::port (spec/and pos-int? (partial > 65535)))
(spec/valid? ::port 4) ; => true
(spec/valid? ::port 0) ; => false
(spec/def ::text-or-port (spec/or ::text ::port))
(spec/valid? ::text-or-port 5) ; => true
(spec/valid? ::text-or-port "hi") ; => false
出于某种原因,它只接受端口号而不接受文本,为什么会这样?
理解这个问题的关键可以在documentation和使用spec/conform
中找到。
(spec/conform ::text-or-port 5)
; => [:user/text 5]
问题是 clojure.spec.alpha/or
有一个 API 与 clojure.core/or
不同,它给出了两个参数 returns 第一个真实的:
(#(or (string? %) (integer? %)) 5) ; => true
(#(or (string? %) (integer? %)) "") ; => true
(#(or (string? %) (integer? %)) :a) ; => false
而是需要成对的标签和 specs/predicates。而且由于甚至命名空间关键字也被接受为标签,因此 OP 中给出的 ::text-or-port
规范仅匹配通过 ::port
要求并为其赋予标签 ::text
的规范。以下是我们要匹配的正确规范:
(spec/def ::text-or-port (spec/or :text ::text
:port ::port))
(spec/valid? ::text-or-port "hi") ; => true
(spec/valid? ::text-or-port 10) ; => true