问题描述
具有以下两个规格:
(s/def ::x keyword?)
(s/def ::y keyword?)
(s/def ::z keyword?)
(s/def ::a
(s/keys :req-un [::x
::y]
:opt-un [::z]))
(s/def ::b
(s/map-of string? string?))
如何将::a
和::b
合并到::m
中,以便以下数据有效:
(s/valid? ::m
{:x :foo
:y :bar
:z :any})
(s/valid? ::m
{:x :foo
:y :bar})
(s/valid? ::m
{:x :foo
:y :bar
:z :baz})
(s/valid? ::m
{:x :foo
:y :bar
:z "baz"})
(s/valid? ::m
{:x :foo
:y :bar
:t "tic"})
此外,如何将::a
和::b
合并到::m
中,所以以下数据无效:
(s/valid? ::m
{"r" "foo"
"t" "bar"})
(s/valid? ::m
{:x :foo
"r" "bar"})
(s/valid? ::m
{:x :foo
:y :bar
:r :any})
都不是:
(s/def ::m (s/merge ::a ::b))
(s/def ::m (s/or :a ::a :b ::b))
可以正常工作(按预期),但是有一种方法可以按照规范顺序的优先级来匹配地图条目?
其工作方式如下:
解决方法
您可以通过将地图不视为地图而是作为地图条目的集合来处理,然后验证地图条目。处理“必需”键部分必须通过添加附加谓词来完成。
(s/def ::x keyword?)
(s/def ::y keyword?)
(s/def ::z keyword?)
(s/def ::entry (s/or :x (s/tuple #{::x} ::x)
:y (s/tuple #{::y} ::y)
:z (s/tuple #{::z} ::z)
:str (s/tuple string? string?)))
(defn req-keys? [m] (and (contains? m :x) (contains? m :y)))
(s/def ::m (s/and map? (s/coll-of ::entry :into {}) req-keys?))