## 元數據
Clojure里面的元數據是附加到一個符號或者集合的一些數據,它們和符號或者集合的邏輯數據沒有直接的關系。兩個邏輯上一樣的方法可以有不同的元數據。 下面是一個有關撲克牌的例子
```
(defstruct card-struct :rank :suit)
(def card1 (struct card-struct :king :club))
(def card2 (struct card-struct :king :club))
(println (== card1 card2)) ; same identity? -> false
(println (= card1 card2)) ; same value? -> true
(def card2 #^{:bent true} card2) ; adds metadata at read-time
(def card2 (with-meta card2 {:bent true})) ; adds metadata at run-time
(println (meta card1)) ; -> nil
(println (meta card2)) ; -> {:bent true}
(println (= card1 card2)) ; still same value despite metadata diff. -> true
```
一些元數據是Clojure內部定義的。比如 `:private` 它表示一個Var是否能被包外的函數訪問。 `:doc` 是一個 Var 的文檔字符串。 `:test` 元數據是一個Boolean值表示這個函數是否是一個測試函數。
`:tag` 是一個字符串類型的類名或者一個 `Class` 對象,表示一個Var在Java里面對應的類型,或者一個函數的返回值。這些被稱為“類型提示” 。提供這些可以提高代碼性能。如果你想查看你的clojure代碼里面哪里使用反射來決定類型信息 -- 也就是說這里可能會有性能的問題, 那么你可以設置全局變量 `*warn-on-reflection*` 為 `true` 。
一些元數據會由Clojure的編譯器自動地綁定到Var對象。 `:file` 是定義這個 Var的文件的名字。 `:line` 是定義這個Var的行數。 `:name` 是一個Var的名字的 `Symbol` 對象。 `:ns` 是一個 `Namespace` 對象描述這個Var所在的名字空間。 `:macro` 是一個標識符標識這個符號是不是一個宏。 `:arglist` 是一個裝有一堆vector的一個list, 表示一個函數所接受的所有的參數列表(前面在介紹函數的時候說過一個函數可以接受多個參數列表)。
函數以及宏,都是有一個 `Var` 對象來表示的, 它們都有關聯的元數據。比如輸入這個在REPL里面: `(meta (var reverse))` 或者 `^#'reverse` 。輸出結果應該下面這些類似(為了好看我加了換行縮進)
```
{
:ns #<Namespace clojure.core>,
:name reverse,
:file "core.clj",
:line 630,
:arglists ([coll]),
:doc "Returns a seq of the items in coll in reverse order. Not lazy."
}
```
clojure.repl包里面的 `source` 函數, 利用元數據來獲取一個指定函數的源代碼,比如:
```
(source reverse)
```
上面代碼的輸出應該是:
```
(defn reverse
"Returns a seq of the items in coll in reverse order. Not lazy."
[coll]
(reduce conj nil coll))
```