用途

定义、校验数据的结构,并生成数据

引入

# project.clj
[org.clojure/clojure "1.11.1"]
# head
(require '[clojure.spec.alpha :as s])
# or 
(ns my.ns (:require [clojure.spec.alpha :as s]))

函数

断言

是否符合规范

(s/conform even? 1000)
=> 1000
(s/conform even? 1001)
=> :clojure.spec.alpha/invalid

(s/vaild? even? 10)
=> true
(s/vaild? even? 11)
=> false

注册

定义规范

(s/def :order/date inst?)
(s/def :deck/suit #{:club :diamond :heart :spade})

(s/valid? :order/date (Date.)) 
;;=> true 
(s/conform :deck/suit :club)
;;=> :club

组合规范

  • s/and 组合同时达成的断言
  • s/or 组合任意达成的断言

    (s/def :num/big-even (s/and int? even? #(> % 1000))) 
    (s/valid? :num/big-even :foo) 
    ;; false 
    (s/valid? :num/big-even 10) 
    ;; false 
    (s/valid? :num/big-even 100000) 
    ;; true
    
    (s/def :domain/name-or-id (s/or :name string? :id int?)) 
    (s/valid? :domain/name-or-id "abc")
    ;; true 
    (s/valid? :domain/name-or-id 100) 
    ;; true 
    (s/valid? :domain/name-or-id :foo) 
    ;; false
    
    (s/conform :domain/name-or-id "abc") 
    ;;=> [:name "abc"] 
    (s/conform :domain/name-or-id 100)
    ;;=> [:id 100]
    
    
    ; for nil problem
    (s/valid? string? nil) 
    ;;=> false 
    (s/valid? (s/nilable string?) nil) 
    ;;=> true

追溯原因

(s/explain :deck/suit 42) 
;; 42 - failed: #{:spade :heart :diamond :club} spec: :deck/suit 
(s/explain :num/big-even 5) 
;; 5 - failed: even? spec: :num/big-even 
(s/explain :domain/name-or-id :foo) 
;; :foo - failed: string? at: [:name] spec: :domain/name-or-id 
;; :foo - failed: int? at: [:id] spec: :domain/name-or-id

键值规范

clojure.spec.alpha的s/keys方法是用于创建和返回一个验证map的规范。它接受以下参数:
:req:一个包含必须存在的键的向量,键必须是命名空间限定的关键字
:opt:一个包含可选存在的键的向量,键必须是命名空间限定的关键字
:req-un:一个包含必须存在但不需要命名空间限定的键的向量
:opt-un:一个包含可选存在但不需要命名空间限定的键的向量
:gen:一个函数,用于生成符合规范的map


(s/def ::even integer? even?)
(s/def ::odd integer? odd?)

(s/valid? (s/coll-of ::even) [2 4 6]) ; true
(s/valid? (s/tuple ::even ::odd) [2 3]) ; true
(s/valid? (s/cat :e1 ::even :o1 ::odd) [2 3]) ; true
(s/valid? (s/alt :e1 ::even :o1 ::odd) [2]) ; true


(s/def :unq/person
    (s/keys :req-un [:acct/first-name :acct/last-name :acct/email]
                :opt-un [:acct/phone])) 

;不需要命名空间限定
(s/conform :unq/person 
{:first-name "Bugs" :last-name "Bunny" :email "bugs@example.com"}) 
;;=> {:first-name "Bugs", :last-name "Bunny", :email "bugs@example.com"}

:: 语法糖

::在clojure.spec.alpha里是一个语法糖,用于表示当前命名空间下的一个规范名称。例如,如果当前命名空间是my.ns,那么::foo就相当于:my.ns/foo。这样可以避免重复输入命名空间的前缀,也可以避免规范名称的冲突。例如:

标签: none

仅有一条评论

  1. 专注于为企业提供从需求分析到系统实施的全流程信息化建设服务。
    http://mip.jadxl.cn/

添加新评论