## 引用類型
引用類型是一種可變引用指向不可變數據的一種機制。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)` |