fra*_*ank 3 clojure clojure.spec
我正在使用 clojure.spec 来验证地图条目的向量。向量看起来像:
[{:point {:x 30 :y 30}}
{:point {:x 34 :y 33}}
{:user "joe"}]
Run Code Online (Sandbox Code Playgroud)
我想将规范结构化为需要 1..N::point个条目并且只有一个::user条目。
这是我构建这个规范的(失败的)尝试:
(s/def ::coord (s/and number? #(>= % 0)))
(s/def ::x ::coord)
(s/def ::y ::coord)
(s/def ::point (s/keys :req-un [::x ::y]))
(s/def ::user (s/and string? seq))
(s/def ::vector-entry (s/or ::pt ::user))
(s/def ::my-vector (s/coll-of ::vector-entry :kind vector))
Run Code Online (Sandbox Code Playgroud)
当我只运行一个::point条目的验证时,它可以工作:
spec> (s/valid? ::point {:point {:x 0 :y 0}})
true
spec> (s/valid? ::my-vector [{:point {:x 0 :y 0}}])
false
Run Code Online (Sandbox Code Playgroud)
关于如何构造s/or部件以便向量条目可以是任何一种::user或::point多种类型的任何想法?
另外,关于如何要求向量中只有一个::user条目和 1..N::point个条目的任何想法?
以下是您问题中数据的可能规格:
(require '[clojure.spec.alpha :as s])
(s/def ::coord nat-int?)
(s/def ::x ::coord)
(s/def ::y ::coord)
(s/def ::xy (s/keys :req-un [::x ::y]))
(s/def ::point (s/map-of #{:point} ::xy))
(s/def ::username (s/and string? seq))
(s/def ::user (s/map-of #{:user} ::username))
(s/def ::vector-entry (s/or :point ::point :user ::user))
(s/def ::my-vector (s/coll-of ::vector-entry :kind vector))
(s/valid? ::point {:point {:x 0 :y 0}})
(s/valid? ::my-vector [{:point {:x 0 :y 0}}])
(s/valid? ::my-vector [{:point {:x 0 :y 0}} {:user "joe"}])
Run Code Online (Sandbox Code Playgroud)
一些观察:
or规范要求,规范给出的名字。:point或:user需要一个间接级别,我map-of在顶部和keys嵌套级别使用,但有很多选择:user需要时,为什么要强制程序进行 O(N) 搜索?希望这可以帮助!