内容简介:首先添加依赖, 因为我在 ClojureScript 当中用, 所以用了首先是一个很简单觉得例子, 有
工具当中需要检测数据格式, 试着用了一下 Clojure Spec.
如果英文好, 直接看文档就行了, 也不用这篇笔记, 太琐碎了, 也缺失例子...
https://clojure.org/guides/sp...
首先添加依赖, 因为我在 ClojureScript 当中用, 所以用了 cljs.spec
这个代码.
expound 是一个用于美化 Spec 输出的类库, 直接引用进来.
[cljs.spec.alpha :as s] [expound.alpha :refer [expound]]
首先是一个很简单觉得例子, 有 s/valid?
判断数据是否符合格式.
首先用 s/def
定义好一个校验的规则, 其中 ::example
会按照命名空间展开.
(s/def ::example boolean?) (println (s/valid? ::example 1)) ; false (println (s/valid? ::example true)) ; true
基础的校验用的是函数, 也可以是 string?
.
s/conform
表示返回输出的值.. 当然这个是正确的情况, 返回了匹配到的字符串,
(s/def ::example string?) (println (s/conform ::example "DEMO")) ; DEMO
如果不匹配, 返回值就是 invalid,
(println (s/conform number? ""))
:cljs.spec.alpha/invalid
可以通过 s/explain
来打印失败的原因,
(s/def ::example string?) (println (s/explain ::example 1)) ; 1 - failed: string? spec: :app.main/example
可以看到这个原因比较精确, 但是可读性不怎么样, 就可以用 expound
替换了, 可读性会好很多,
(s/def ::example string?) (println (expound ::example 1))
-- Spec failed -------------------- 1 should satisfy string? -- Relevant specs ------- :app.main/example: cljs.core/string? ------------------------- Detected 1 error
既然校验规则是函数, 也可以写成,
(s/def ::example #(and (> % 6) (< % 20))) (println (s/valid? ::example 1)) ; false (println (s/valid? ::example 10)) ; true (println (s/valid? ::example 20)) ; false
校验规则也可以组合使用, 最简单就是 s/or
, 注意参数中奇数位置都用的 keyword,
(s/def ::example (s/or :as-number number? :as-boolean boolean?)) (let [data 0] (if (s/valid? ::example data) (println (s/conform ::example data)) (println (expound ::example data)))))
打印的结果是,
[:as-number 0]
s/or
里直接用函数式简写了, 可以专门定义两个规则出来, 然后再使用,
(s/def ::boolean boolean?) (s/def ::number number?) (s/def ::example (s/or :as-number ::number :as-boolean ::boolean)) (if (s/valid? ::example 20) (println (s/conform ::example 20)) (println (expound ::example 20)))
返回依然得到数据,
[:as-number 20]
对于数组的结构的数据, 用 s/coll-of
来判别,
(s/def ::number number?) (s/def ::example (s/coll-of ::number)) (let [data [1]] (if (s/valid? ::example data) (println (s/conform ::example data)) (println (expound ::example data))))
得到,
[1]
s/coll-of
还支持比如 :count
这样的校验, 具体可以再看文档,
(s/def ::example (s/coll-of number? :count 2)) (defn task! [] (let [data [1]] (if (s/valid? ::example data) (println (s/conform ::example data)) (println (expound ::example data)))))
-- Spec failed -------------------- [1] should satisfy (= 2 (count %)) -- Relevant specs ------- :app.main/example: (cljs.spec.alpha/coll-of cljs.core/number? :count 2) ------------------------- Detected 1 error
对于 Map, 用 s/keys
来判断, :req-un
表示必选项, opt-un
是可选项,
(s/def ::age number?) (s/def ::name string?) (s/def ::example (s/keys :req-un [::age] :opt-un [::name])) (let [data {:age 1, :name "a"}] (if (s/valid? ::example data) (println (s/conform ::example data)) (println (expound ::example data))))
得到,
{:age 1, :name a}
如果不满足校验规则, 会准确提示出来, 比如可选项的规则不满足,
(s/def ::age number?) (s/def ::name string?) (s/def ::example (s/keys :req-un [::age] :opt-un [::name])) (let [data {:age 1, :name 1}] (if (s/valid? ::example data) (println (s/conform ::example data)) (println (expound ::example data))))
-- Spec failed -------------------- {:age ..., :name 1} ^ should satisfy string? -- Relevant specs ------- :app.main/name: cljs.core/string? :app.main/example: (cljs.spec.alpha/keys :req-un [:app.main/age] :opt-un [:app.main/name]) ------------------------- Detected 1 error
上面用到的 -un
的后缀表示 "unqualified", 如果没有后缀, 意味着 keyword 要根据命名空间展开,
(s/def ::age number?) (s/def ::name string?) (s/def ::example (s/keys :req [::age] :opt [::name])) (let [data {:age 1, :name 1}] (if (s/valid? ::example data) (println (s/conform ::example data)) (println (expound ::example data))))
于是就不满足了,
-- Spec failed -------------------- {:age 1, :name 1} should contain key: :app.main/age | key | spec | |---------------+---------| | :app.main/age | number? | -- Relevant specs ------- :app.main/example: (cljs.spec.alpha/keys :req [:app.main/age] :opt [:app.main/name]) ------------------------- Detected 1 error
就需要改写一下 key, 也用 ::x
的语法带上命名空间,
(s/def ::age number?) (s/def ::name string?) (s/def ::example (s/keys :req [::age] :opt [::name])) (let [data {::age 1, ::name "a"}] (if (s/valid? ::example data) (println (s/conform ::example data)) (println (expound ::example data))))
得到,
{:app.main/age 1, :app.main/name a}
Spec 也可以对字符串进行校验, 同时也可以解析得到数据,
其中需要用到 (s/conformer seq)
来对字符串进行转化...
这个写法目前我也不够清晰, 参考了一下例子,
https://gist.github.com/thege...(s/def ::left-paren #{"("}) (s/def ::right-paren #{")"}) (s/def ::space (s/and string? (s/conformer seq) (s/+ #{" "}))) (s/def ::token (s/and string? (s/conformer seq) (s/+ #{"a" "b" "c"}))) (s/def ::example (s/cat :left-paren ::left-paren :expr (s/+ (s/or :token ::token :space ::space)) :right-paren ::right-paren)) (let [data (seq "(a b)")] (if (s/valid? ::example data) (println (pr-str (s/conform ::example data))) (println (s/explain ::example data))))
最终得到,
{:left-paren "(", :expr [[:token ["a"]] [:space [" "]] [:token ["b"]]], :right-paren ")"}
更多
这里没有罗列 Entity Map 校验的写法. 也没有展示 generation 的效果. 丢了很多东西.
以上所述就是小编给大家介绍的《尝试 Clojure Spec 的笔记》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++数据结构与程序设计
克鲁斯 / 钱丽萍 / 清华大学出版社 / 2004-1 / 59.00元
《C++数据结构与程序设计》这本精心制作的课本结合面向对象程序设计和C++强有力的特性,构建数据结构的基本思想,设计了程序和有趣的应用。在此过程中,《C++数据结构与程序设计》探讨了作为软件设计基本工具的问题求解和设计原理、数据抽象、递归和算法的比较分析。《C++数据结构与程序设计》使用真实的案例研究、可重用的软件开发和程序设计项目来增强理解。一起来看看 《C++数据结构与程序设计》 这本书的介绍吧!