请分享您的看法,参加 2024 Clojure 状态调查!

欢迎!请参阅关于页面以获取更多关于如何使用本网站的信息。

+2
Spec
编辑

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

(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 标签。同样,也不能将 :req-un [:e1/entity]:req-un [:e2/entity] 添加到 ::e1::e2,因为这会在 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

我遇到过这种情况,最终没有使用多方法来解决这个问题。相反,我将为每个可能的子类型定义规范(包括为您的案例设置一个常量值 :entity),然后使用 s/or 创建一个总的规范。这样,我可以在需要时使用子规范,或者如果我想引用整个集合,我可以使用 s/or 规范。

...