Clojure如何基于请求数据动态定义spec规范
Clojure动态定义Spec的正确实现方法
问题根因
s/def 是编译期执行的宏,它会直接处理传入的第一个参数:如果传入的是符号,会直接将该符号转为当前命名空间下的关键字,不会在运行时读取符号对应Var的值,这就是你之前所有写法失效的核心原因。
可行解决方案
方案1:用eval包装完整s/def表达式
这是最直观、和手动写s/def效果完全一致的方案:
(require '[clojure.spec.alpha :as s]) (def my-key :frame-data/pretty_name) (def validator string?) ;; 运行时生成并执行s/def表达式 (eval `(s/def ~my-key ~validator))
反引号 + 波浪号的语法会先把my-key和validator的运行时值插入到表达式中,再交给eval执行,最终效果和你手动写(s/def :frame-data/pretty_name string?)完全一致。
方案2:直接调用s/def底层实现函数
clojure.spec.alpha 公开了运行时定义spec的底层函数s/def-impl,不需要走宏编译流程,更适合批量动态生成spec的场景:
;; 三个参数分别为:目标关键字、校验器、s/describe返回的表单 (s/def-impl my-key validator (list 'quote validator))
效果验证
执行完上述代码后可以通过以下代码确认生效:
;; 校验符合预期 (s/valid? :frame-data/pretty_name "用户昵称") ; => true (s/valid? :frame-data/pretty_name 12345) ; => false ;; 描述符合预期 (s/describe :frame-data/pretty_name) ; => string?
内容的提问来源于stack exchange,提问作者TankorSmash
相关产品推荐
相关产品推荐

