Clojure

元資料

符號和集合支援元資料,即關於符號或集合的資料對應。元資料系統允許任意註解資料。它用於傳達關於型別的資訊給編譯器,但應用程式開發人員也可以用於許多目的,例如註解資料來源、政策等。

關於元資料需要了解的一件重要事情是,它不被視為物件值的一部分。因此,元資料不會影響相等性(或雜湊碼)。僅在元資料上有所不同的兩個物件是相等的。

話雖如此,元資料及其與物件的關係是不可變的 - 具有不同元資料的物件是不同的物件。這其中一個後果是,將元資料套用到延遲序列將實現序列的開頭,以便兩個物件可以共用相同的序列。


(meta obj)

傳回 obj 的元資料,如果沒有元資料,則傳回 nil。

(pprint (meta #'+)) ;; #'+ is the + var

;; {:added "1.2",
;;  :name +,
;;  :file "clojure/core.clj",
;;  :column 1,
;;  :line 984,
;;  :arglists ([] [x] [x y] [x y & more]),
;;  ...

(with-meta obj map)

傳回與 obj 類型和值相同的物件,其 metadata 為 map。

(def m ^:hi [1 2 3])
(meta (with-meta m {:bye true}))
;; {:bye true}

*print-meta*

如果設定為邏輯 true,在列印物件時,其 metadata 也會以可由讀取器讀回的格式列印出來。

(def m ^:hi [1 2 3])
(binding [*print-meta* true]
  (prn m))

;; ^{:hi true} [1 2 3]

(vary-meta obj f & args)

傳回與 obj 類型和值相同的物件,其 metadata 為 (apply f (meta obj) args)

(def m ^:hi [1 2 3])
(meta (vary-meta m merge {:bye true}))
;; {:hi true, :bye true}

(alter-meta! ref f & args) 和 (reset-meta! ref map)

分別修改或重設命名空間/變數/參照/代理/原子的 metadata。

Metadata 讀取器巨集

除了 with-meta 之外,還有一些讀取器巨集 (讀取器:巨集字元),用於在讀取時將 metadata 套用至其後的表達式

  • ^{:doc "How it works!"} - 將 metadata map 新增至下一個讀取值的 metadata

  • ^:dynamic - 類似於 ^{:dynamic true}

  • ^String - 類似於 ^{:tag java.lang.String}

  • ^"java.lang.String" - 類似於 ^{:tag java.lang.String}

:tag 鍵用於向 Clojure 編譯器提示物件的類型。請參閱 Java Interop:類型提示 以取得更多資訊和完整的特殊類型提示清單。

可以透過將 metadata 讀取器巨集串連在一起來新增多個 metadata。例如:^:dynamic ^ints obj 會同時將 :dynamic 旗標和 ints 類型提示套用至 obj。Metadata 鏈從右至左 (左方優先)。

請注意,metadata 讀取器巨集是在讀取時套用,而不是在評估時,而且只能用於支援 metadata 的值,例如符號、變數、集合、序列、命名空間、參照、原子、代理等。一些不支援 metadata 的重要例外包括字串、數字、布林值、Java 物件、關鍵字 (這些會快取,且可以在執行期間內共用) 和 deftypes (除非它們明確實作 clojure.lang.IMeta)。