分类 默认分类 下的文章

用途

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

引入

# 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。这样可以避免重复输入命名空间的前缀,也可以避免规范名称的冲突。例如:

数据库解构
今天的绝大多数数据库都反映了几十年前的设计,当时内存和磁盘非常小,而且非常昂贵。现在,它们的容量和成本都提高了一百万倍,因此应该重新审视数据库设计的许多假设。最重要的是,过去的数据库是根据更新位置来定义的,以节省磁盘空间和内存。如果我们要从小型的效率转向大型的能力,就需要放弃面向位置的编程。
有趣的是,我们在谈论更新就地数据库时使用了“内存”和“记录”这两个术语,因为过去的记录(早于计算机)实际上并没有随着新记录的产生而被删除。我们也不会为了形成新的记忆而抹去旧的心理记忆。我们很可能会回顾20世纪的最后几十年,这是一个不幸的时代,当时计算机的经济性使我们无法做正确的事情。现在是改变这种状况的时候了。

传统上,数据库被要求提供以下服务等:
协调
一致性
索引
存储
查询

现代云架构的下一代应用程序需要可伸缩、灵活且智能化的分布式数据库,而Datomic就是为此而设计的。它可以让应用程序更加高效地运行,并且可以轻松地适应不断变化的数据需求。无论是在企业级应用、金融领域还是其他领域,Datomic都是一种值得信赖的解决方案。

Datomic的特点在于:

  • 引入声明式数据操作,将数据与应用程序相结合;
  • 正确处理时间、进程和感知;
  • 处理进程(写入)需要协调,而处理感知(读取)则不需要;
  • 协调:一组进程协商谁负责处理Datomic系统中各种角色的能力
  • 角色:对于交易方、持久性、同类服务等的通称
  • 过去不会改变;
  • 利用不可变性和稳健的状态模型

Datomic优势

ACID事务
连接操作
健全的数据模型
逻辑查询语言Datalog
这些功能使得Datomic避免了许多NoSQL解决方案中的妥协和损失。
此外,相较于传统模型,Datomic在支持灵活性和强大性方面也更具优势。
层级
多值属性
最小化模式
在不可靠的、短暂的云实例上进行可靠的操作
时间
Datomic通过避免手动缓存和复制、复杂的配置、分片、日志、锁定和磁盘管理等传统服务器的问题,实现了更加简便的操作

Clojure的设计原则可以概括为五个词汇:简单、专注、实用、一致和清晰。Clojure是一种基于LISP编程语言设计的高级、动态的函数式编程语言。它结合了脚本语言的可读性和交互式开发,以及多线程编程的高效和稳健的基础设施。