【问题标题】:Spec a collection to have exactly one of each values将集合指定为每个值中的一个
【发布时间】:2019-03-11 11:13:50
【问题描述】:

有这张地图:

{:id 5
 :fields [{:field :a :val 1}
          {:field :c :val 3}
          {:field :b :val 2}
          {:field :d :val 4}
          ...]}

并为每个字段值单独指定规范,例如 (s/def ::field-a ...)(s/def ::field-b ...)(s/def ::field-c ...)

我应该如何指定它以便地图中的:fields 包含{:field a ...}{:field b ...}{:field c ...}(不考虑顺序)中的每一个(并且恰好是一个)以及可选的其他值?

【问题讨论】:

标签: clojure clojure.spec


【解决方案1】:

是的,我知道它有点庞大,但无论如何:

(s/def ::id int?)
(s/def ::val int?)
(s/def ::field keyword?)
(s/def ::some string?)

(s/def ::abstract-field (s/keys :req-un [::field ::val]))

(s/def ::field-a (s/and (s/keys :req-un [::field ::val]) #(= (:field %) :a)))
(s/def ::field-b (s/and (s/keys :req-un [::field ::val]) #(= (:field %) :b)))
(s/def ::field-c (s/and (s/keys :req-un [::field ::val]) #(= (:field %) :c)))
(s/def ::field-d (s/and (s/keys :req-un [::field ::val]) #(= (:field %) :d)))

(s/def ::fields (s/and
                    (s/+ (s/alt :required (s/or :a ::field-a
                                                :b ::field-b
                                                :c ::field-c
                                                :d ::field-d)
                                :rest ::abstract-field))
                    (fn [x] (= [:a :b :c :d]
                               (into [] (sort (map (comp first second) (filter #(= :required (first %)) x))))))))

(let [x1 [{:field :b :val 2}
          {:field :a :val 1}
          ;{:field :a :val 1}
          {:field :d :val 4}
          {:field :e :val 4}
          {:field :c :val 3}
          ]]
    (s/explain ::fields x1)
    (s/conform ::fields x1))

【讨论】:

  • 该死,这是一个大规格! :D 我希望有一些简洁的解决方案,但我想没有其他方法可以解决它。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2016-02-28
  • 1970-01-01
  • 1970-01-01
  • 2017-10-10
  • 2016-12-13
  • 2010-12-25
  • 1970-01-01
  • 2014-02-12
相关资源
最近更新 更多