如何使用Clojure.spec定义嵌套序列/向量的规范?
如何用Clojure.spec正确定义嵌套序列/向量的规范
你的问题出在cat的行为上:cat是用来匹配平铺的序列元素,而非嵌套的子序列。当你在内层使用(s/cat :int int?)时,spec会把它当成需要平铺到父序列中的元素规则,所以会尝试把[1]直接匹配int?,导致校验失败。
修复方案
以下几种方式都可以正确定义嵌套序列的规范:
1. 用s/spec包裹内层cat
s/spec会将内层规范包装成一个独立的校验单元,告诉spec这个位置是一个需要整体校验的子序列:
(s/def ::test (s/cat :s any? :r (s/spec (s/cat :int int?)))) (s/explain-str ::test ["test" [1]]) ;; 返回空字符串,说明校验通过
2. 直接使用序列类型规范
如果明确知道内层是向量或特定类型的序列,可以用s/vector-of、s/coll-of这类更精准的规范:
;; 匹配包含单个int的向量 (s/def ::test (s/cat :s any? :r (s/vector-of int?))) (s/explain-str ::test ["test" [1]]) ;; 校验通过 ;; 匹配包含恰好一个int的任意序列 (s/def ::test (s/cat :s any? :r (s/coll-of int? :count 1))) (s/explain-str ::test ["test" [1]]) ;; 校验通过
3. 用s/and结合序列判断
如果需要更灵活的嵌套结构校验,可以先判断该位置是序列,再应用内层规范:
(s/def ::test (s/cat :s any? :r (s/and sequential? (s/cat :int int?)))) (s/explain-str ::test ["test" [1]]) ;; 校验通过
核心逻辑
cat的设计目标是组合多个规范来匹配连续平铺的元素(比如["test" 1]这种结构)。当你需要匹配嵌套的子序列时,必须显式标记该位置是一个独立的子序列单元,通过s/spec或序列类型规范来实现这一点。
内容的提问来源于stack exchange,提问作者Joerg Schmuecker
相关产品推荐
相关产品推荐

