## 元数据
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))
```