【问题标题】:Specify content of a submap based on a field基于字段指定子图的内容
【发布时间】:2017-10-30 09:52:18
【问题描述】:

也许我的问题已经得到解答,但我被子图规范困住了。

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

{: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 是不可访问的。 所以我想制作一个更高级别的多规格(基于整个地图)。

问题:我不知道如何根据:type 定义:spec,因为它们具有相同的名称。你知道怎么做吗?

谢谢

【问题讨论】:

    标签: clojure clojure.spec


    【解决方案1】:
    (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"}} ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-17
      相关资源
      最近更新 更多