本文参考自http://java.ociweb.com/mark/clojure/article.html#Metadata
也许你在别的计算机语言中见过元数据这一概念,但Clojure中的元数据,也即Metadata有其独有的含义。Clojure里面的Metadata是附加到一个符号或者集合上的一些数据,它们和符号或者集合的逻辑数据没有直接的关系。两个逻辑上一样的方法可以有不同的元数据。比如两张扑克牌都是梅花K,Metadata是用于指示那张牌是横向着的,事实上对于大多数扑克牌游戏,扑克牌的倾斜与否对扑克牌所表示数值根本没有影响。如下图所示:
(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有一个boolean值,用于指示在定义某个Var对象的Namespace中是否
访问受限。:doc则是一个Var对象的文档字符串。:test则有一个用于指示一个不接受外部参数的函数是否为一个测试函
数。:tag是一个String类型的类名或者一个Class 对象,表示一个Var在Java里面对应的类型,抑或是一个函数的返回类
型。这些都是被作为类型提示。提供这些元数据能够提高性能。
如果你想查看你的clojure代码里面哪里使用反射来决定类型信息 -- 也就是说这里可能会有性能的问题, 那么你可以设置
全局变量*warn-on-reflection* 为true。
Clojure编译器会自动将某些元素附加到Var对象上。
:file是定义Var对象的那个文件的字符串名称。:line则是文件中定义Var对象所在的行数。:name是给Var对象提供名称的一
个Symbol。:ns是一个Namespace对象,描述了定义Var对象的Namespace。:macro则是一个指示Var对象是一个宏而非函
数或者绑定变量。:arglist是一序列向量,每个向量都描述了一个函数所能够接受的参数名称。记住,一个函数可以有多个参
数列表和函数体。函数或者宏都是由一个Var对象来表示,有各自相关联的元数据。
例如在REPL环境中输入 (meta (var 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." }
(defn reverse "Returns a seq of the items in coll in reverse order. Not lazy." [coll] (reduce conj nil coll))