## 引用类型
引用类型是一种可变引用指向不可变数据的一种机制。Clojure里面有4种引用类型:Vars,Refs,Atoms和Agents. 它们有一些共同的特征:
* 它们都可以指向任意类型的对象。
* 都可以利用函数 `deref` 以及宏 `@` 来读取它所指向的对象。
* 它们都支持验证函数,这些函数在它们所指向的值发生变化的时候自动调用。如果新值是合法的值,那么验证函数简单的返回true, 如果新值是不合法的,那么要么返回false, 要么抛出一个异常。如果只是简单地返回了 `false` , 那么一个 `IllegalStateException` 异常会被抛出,并且带着提示信息: "Invalid reference state" 。
* 如果是Agents的话,它们还支持watchers。如果被监听的引用的值发生了变化,那么Agent会得到通知, 详情见 "Agents" 一节。
下面的这个表格总结了一下四种引用类型的区别,以及分别要用什么方法去创建或者修改它们。这个表格里面提到的函数我们会在后面介绍。
| | Var | Ref | Atom | Agent |
| --- | --- | --- | --- |
| 目的 | 同步对于一个线程本地(thread-local)的变量的修改。 | 同步、协调对于一个或者多个值的修改 | 同步对于一个值的修改 | 对一个值进行异步修改 |
| 创建方法 | `(def name initial-value)` | `(ref initial-value)` | `(atom initial-value)` | `(agent initial-value)` |
| 修改方法 | `(def name new-value)` - 可以赋新的值 `(alter-var-root (var name) update-fn args)` - 自动设置新值 `(set! name new-value) - 在一个binding form 里满设置一个新的、线程本地的值` | `(ref-set ref new-value)` - `必须在dosync里面调用` `(alter ref update-fn arguments)` - `必须在dosync里面调用` `(commute ref update-fn arguments)` - 必须在 `dosync 里面调用` | `(reset! atom new-value)` `(compare-and-set! atom current-value new-value)` `(swap! atom update-fn arguments)` | `(send agent update-fn arguments)` `(send-off agent update-fn arguments)` |