1

也许我的问题已经得到解答,但我坚持使用子图规范。

想象一下我有两种这样的可能性

{:type :a
 :spec {:name "a"}}

{:type :b
 :spec {:id "b"}}

简而言之::spec密钥取决于类型。对于类型:a:spec必须包含字段:name,对于类型:b,规范必须包含字段:id

我试过这个:

(s/def ::type keyword?)

(defmulti input-type ::type)
(defmethod input-type :a
  [_]
  (s/keys :req-un [::name]))
(defmethod input-type :b
  [_]
  (s/keys :req-un [::id]))
(s/def ::spec (s/multi input-type ::type))

(s/def ::input (s/keys :req-un [::type ::spec]))

这告诉我:没有方法([:spec nil])。我想我明白为什么了:也许 type 是不可访问的。所以我想制作一个更高级别的多规格(基于整个地图)。

问题:我不知道如何定义:spec基于,:type因为它们具有相同的名称。您知道如何执行此操作吗?

谢谢

4

1 回答 1

0
(s/def ::type keyword?)
(s/def ::id string?)
(s/def ::name string?)
(s/def :id/spec (s/keys :req-un [::id]))
(s/def :name/spec (s/keys :req-un [::name]))

为了适应您的地图的两种不同含义:spec,我们可以在不同的命名空间中定义它们::id/spec:name/spec. 请注意,这些关键字的非命名空间后缀都是spec,我们的keys规范使用的是非命名空间关键字。这些是“假”命名空间,但您也可以在项目中的其他“真实”命名空间中定义它们。

(defmulti input-type :type)
(defmethod input-type :a [_]
  (s/keys :req-un [::type :name/spec]))
(defmethod input-type :b [_]
  (s/keys :req-un [::type :id/spec]))

(s/def ::input (s/multi-spec input-type :type))

(s/valid? ::input {:type :a, :spec {:name "a"}})
=> true

您还可以获取此规范的示例:

(gen/sample (s/gen ::input))
=>
({:type :a, :spec {:name ""}}
 {:type :b, :spec {:id "aI"}} ...
于 2017-11-30T14:44:08.900 回答