Clojure 2024 状态调查!中分享您的想法。

欢迎!请参阅关于页面,了解更多关于如何使用此功能的信息。

+2
规范
编辑

从多规格中选择一个规格的首选方法是什么?例如。

(defmulti entity :entity)

(s/def ::e1
  (s/keys :req [:e1/attr1
                :e1/attr2
                :e1/attrN]))

(defmethod entity :e1 [_] ::e1)

(s/def ::e2
  (s/merge
   ::e1
   (s/keys :req [:e2/attr1
                 :e2/attr2
                 :e2/attrN])))

(defmethod entity :e2 [_] ::e2)

(s/def ::entity (s/multi-spec entity :entity))

如何为只接受 ::e2 实体作为参数的函数指定规范?... 或者如何生成仅包含 ::e2 实体值?

不能做 (s/cat :e2 ::e2)(s/gen ::e2),因为 ::e2 没有所需的 :entity 标签。同样,不能向 ::e1::e2 添加 :req-un [:e1/entity]:req-un [:e2/entity],因为这将在 s/merge 中冲突。

我找到的最简单方法是使用 s/and,例如

(gen/generate (s/gen (s/and ::entity ::e2)))

但对于接受任何实体的同质集合的函数的生成数据来说,这仍然很困难

(s/and (s/coll-of ::entity :min-count 1)
       #(->> % (map :entity) (apply =)))

如果能传递实体标签以选择特定的实体规范或生成器,将会更容易,例如,生成随机实体,并根据其实体标签生成其他元素。

换句话说,我正在寻找一种方法,通过 :e2 标签以某种方式获取 ::e2 实体规范,而无需维护一个全局辅助映射...

或者有没有其他解决方案?

1 答案

0
by

我一直遇到这个问题,最终没有在当前场景中使用多方法。相反,我将分别为可能的子类型定义规范(包括设置一个常量值,例如在你案例中的 :entity),然后使用 s/or 创建一个整体规范。这样我就可以在使用时使用子规范,或者如果我想引用整体集合,可以使用 s/or 规范。

...