user=> (def x)
#'user/x
user=> x
#object[clojure.lang.Var$Unbound 0x14008db3 "Unbound: #'user/x"]
Clojure 是一種實用的語言,它承認偶爾需要維護對變動值的持續參考,並提供 4 種不同的機制以受控的方式執行此操作 - Vars、Refs、Agents 和 Atoms。Vars 提供一種機制來參考可變儲存位置,該位置可以在每個執行緒的基礎上動態重新繫結(到新的儲存位置)。每個 Var 都可以(但不必)具有根繫結,這是一個由所有沒有每個執行緒繫結的執行緒共用的繫結。因此,Var 的值是其每個執行緒繫結的值,或者,如果它未繫結在請求值的執行緒中,則為根繫結的值(如果有的話)。
特殊形式 def
會建立(並 實習)一個 Var。如果 Var 尚未存在且未提供初始值,則 var 未繫結
user=> (def x)
#'user/x
user=> x
#object[clojure.lang.Var$Unbound 0x14008db3 "Unbound: #'user/x"]
提供初始值會繫結根(即使它已經繫結)。
user=> (def x 1)
#'user/x
user=> x
1
Vars 預設為靜態,但 Vars 可以標記為動態,以允許透過巨集 binding 進行每個執行緒繫結。在每個執行緒中,它們遵守堆疊原則
user=> (def ^:dynamic x 1)
user=> (def ^:dynamic y 1)
user=> (+ x y)
2
user=> (binding [x 2 y 3]
(+ x y))
5
user=> (+ x y)
2
使用 binding
建立的繫結無法被任何其他執行緒看到。同樣地,使用 binding
建立的繫結可以被指定,這提供了一種讓巢狀內容在放置在呼叫堆疊之前與程式碼通訊的方法。此功能僅透過設定元資料標籤:將 ^:dynamic
設定為 true(如上方的程式碼區塊所示)來選擇加入。在某些情況下,您可能希望在內容中重新定義靜態 Vars,而 Clojure(自 1.3 版以來)提供函式 with-redefs 和 with-redefs-fn 來執行此類目的。
使用 defn 定義的函式會儲存在 Vars 中,允許在執行中的程式中重新定義函式。這也啟用了面向切面或面向內容程式設計的許多可能性。例如,您可以在某些呼叫內容或執行緒中僅使用記錄行為來包裝函式。
可以使用 with-local-vars 建立未實例化的變數。在自由符號解析期間找不到這些變數,而且必須手動存取它們的值。但是,它們可以用作有用的執行緒本地可變儲存格。
建立變數 def
、defn
、defmacro
等的表單使用一組標準的變數 元資料 來描述變數。其中一些表單使用明確的語法來接受儲存在元資料中的值,但通常您也可以在變數符號上提供該元資料作為一個映射。
常見的變數元資料金鑰(在變數定義中都是選用的)
:doc
- 記錄變數的字串,通常由文件字串參數設定
:added
- 記錄新增此變數的版本的字串
:private
- 布林旗標,通常由 defn-
設定,由作者用來宣告此變數是實作細節的意圖。私人變數是全域可存取的,但不會在過濾到非私人變數的 ns-
… 函式中被參照或列出。
:arglists
- arglist 的集合,如果未提供,將自動產生,最常被用來記錄巨集語法
:macro
- defmacro
自動新增的布林旗標(通常不直接使用)
:tag
- 變數中值的類型識別碼(通常是類別)或變數中所含函式的傳回類型。請注意,變數元資料會被評估,因此變數上的類型提示(例如 ^long
)會評估為 long
函式,而不是 long
基本類型提示。一般來說,建議在 defn 變數的 arglist 上使用類型提示。
:test
- clojure.test
架構使用此金鑰將單元測試附加到變數(通常不直接使用)
:dynamic
- 表示變數可以在執行緒內容中動態重新繫結(請參閱上方)。使用直接連結編譯時,動態變數不會直接連結。
:redef
- 表示使用直接連結編譯時,不應直接連結變數(因此允許重新定義變數)
:static
- 不再使用(原本變數預設為動態,現在預設為靜態)
:const
- 表示變數為編譯時期常數,編譯器可以將值內聯到使用該值的程式碼中。注意:這很少需要,而且僅適用於編譯時期的常數(讀取,但未評估),例如數字、字串等(非類別、函式、參考類型等)。重新定義或動態繫結常數變數不會影響已編譯並載入執行時期中使用該變數的程式碼。
另請參閱 編譯器選項,以進一步瞭解編譯期間的直接連結和元資料消除。
def
的變體: defn defn- definline defmacro defmethod defmulti defonce defstruct
使用內部化 Vars: declare intern binding find-var var
使用 Var 物件: with-local-vars var-get var-set alter-var-root var? with-redefs with-redefs-fn
Var 驗證器: set-validator! get-validator
使用 Var 元資料: doc find-doc test