clojure实战——schema for clojure

来源:互联网 发布:java 视频播放 编辑:程序博客网 时间:2024/05/16 06:42

一、何为schema

schema是描述数据形式的一种clojure数据结构,可用于文件、校验函数和数据。
下面举个例子让大家对schema有个总体认识,例:

(ns schema-examples    (:require [schema.core :as s]))(def  s-type s/Str)(s/validate  s-type  "123")  ;; Success!(s/validate  s-type  123)   ;; Exception -- Value does not match schema:...

二、schema在clojure中的使用

  • project.clj的:dependencies中添加“[prismatic/schema “0.3.1”]”包。
  • 在命名空间的:require中加入“[schema.core :as s]”。

三、定义数据类型

(1)支持java所定义的所有数据类型(包括基本数据类型和复杂数结构),schema封装了好多Java的数据类型,如Int Str等。详见。例:

(def data long)(def map-shape java.util.Map)

(2)支持schema.core定义的数据类型。例:

(def s-data s/Int)(def s-str s/Str)(def s-keyword s/Keyword)

(3)支持自定义数据类型。例:

(def Data  {:a {:b s/Str      :c s/Int}  :d [{:e s/Keyword       :f [s/Num]}]})

(4)可以利用schema提供的工具函数来定义类型
例:定义一个数据必须是奇数且为长整形的:

(def OddLong (s/both long (s/pred odd? 'odd?)))

(都不用你再写一个检查函数了,很方便啊)
(5)对于Map的schema,在定义的时候还可以设定可选项
如:

(def FancyMap {(s/optional-key :foo) s/Keyword   s/Str s/Str})(s/validate FancyMap {"a" "b"})(s/validate FancyMap {:foo :f "c" "d" "e" "f"})

注意:key 和 value应该是成对出现或消失的。

(s/validate FancyMap {:foo "c" "d" "e" "f"})  ;; Exception -- Value does not match schema:...

(6)你可以用s/validate函数来检测你定义的数据是否满足你定义的类型。还可以用s/explain函数来检查某个类型的定义。
如:

(s/validate FancyMap {"a" "b"})(s/explain FancyMap)

四、定义变量

可以用schema.core中的def来定义一个变量, 如:

(s/def foo :- long 2)

要求用于变量初始化的值必须满足定义的schema.

五、定义函数

schema.core中封装了好多函数, 我们可以利用s/defn或s/fn来定义我们的函数,和用clojure的defn是一样样的。例:

(s/defn deposite :- (s/maybe s/Int) [order-id :- (s/maybe s/Int) pay-type :- s/Str])

(1)如果想要对函数做类型检查,必须使用schema中封装的defn 或 fn来定义函数。这是执行类型检查的基础,但是是否进行类型检查,还有“开关”进行控制。
(2)参数和返回值:可以用”:-“符号来指定一个参数和返回值的类型(可以是自定义类型)。
(3)如果数据可能为nil时,可以用maybe函数来修饰。
(4)如果想要对某个函数或者多个函数进行类型检查,可以用with-fn-validation来执行这些函数。如:

(s/with-fn-validation(deposite 1 "yidong")(function2 ...)(function3 ...))

这个相当于类型检查的“开关”,在测试代码中非常有用。我们可以在测试的时候开启类型检查。而发布的时候则不需要开启。
(5)如果想要一个函数总是执行类型检查,可以使用“^:always-validate”。如:

(s/defn ^:always-validate finish-order :- Map [order-id :- s/Int pay-type :- s/Str pay-result :- s/Bool]

对于那些和用户输入相关的函数,可以使用该方法。

六、schema的好处:

(1)可自定义数据类型。
(2)可自由控制检测开关。
比如,可在测试时打开类型检测,发布时关闭.
(3)明确输入输出, 提高代码可读性。
不需要为函数参数和返回值写一堆注释:注释和代码不同步,自然语言描述的不明确、不一致,在每个使用该数据的地方都要写一次注释.

七、schema的不足:

(1)不能对数组的个数做限定,如果想定义只有两个元素的数组”[Long Long]”.
个人想法:这不能算是不足,因为schema主要是做类型检测的,不是编译器。
(2)不能定义某些复杂的类型,如想要给下面的数据结构定义一个类型:

[[1 1.0] [2 2.0]]

你可能会定义成:

(def a [[s/Int double]])

结果运行(s/validate a [[1 1.0] [2 2.0]])出错.
定义成[[s/Num]]则运行正常.
个人想法:数组中存放的元素的类型应该是一致的(C/C++/JAVA等语言中,数组中元素的类型不都是一致的么?), 你可以把它们封装在一个map或者类里,再来定义。

八、schema支持的clojure版本。

文档上说是1.5.1 and 1.6.x,实际测试发现1.7.0-alpha也支持。
*还支持ClojureScript(有需要的时候再研究,欢迎大家补充).

以上是根据个人实践和查阅资料所总结出来的, 有不足或者错误之处,请大家补充和指正.

0 0
原创粉丝点击