Metadata
identical? 和 java 中的 == 运算符是一个意思。= 和 java 中的 equal 函数是一个意思。
Metadata在Clojure中可以不改变数据的情况下给数据增加metadata,使用with-meta宏和meta宏
(def stu {:name "Stu" :email "stu@thinkrelevance.com"}) (def serializable-stu (with-meta stu {:serializable true}))
那么取数据的结果如下:
(meta stu) nil (meta serializable-stu) {:serializable true}
可以用 ^ 代替 meta 来完成上面的工作
当我们根据一个老对象创建一个新对象的时候,老对象的metadata就会跟随着来到新对象这里。
metadata 可以用来给一个函数指定参数和返回值类型,这在传统的函数式编程中往往是没有的,这点缺失也往往成为函数式语言不适合调试的明证。很幸运的是Clojure通过metadata提供了类似的能力。
比如下文我们定义了一个函数,这个函数的参数和返回值都是String类型的:
(defn #^{:tag String} shout [#^{:tag String} s] (.toUpperCase s))
由于metadata的tag参数太常用,在Clojure中可以简化为下面这个形式:
(defn #^String shout [#^String s] (.toUpperCase s))
这样,当你用一些不是String的参数来调用shout的时候就会爆出下面的错误:
(shout 1) java.lang.ClassCastException: \ java.lang.Integer cannot be cast to java.lang.String
如果你觉得这样定义的函数看起来有点怪异,那么便可以把这个metadata的定义放到最后来做,不过与普通的函数定义有区别的地方在于,我们要用括号包裹起函数体:
(defn shout ([s] (.toUpperCase s)) {:tag String})
下面是一个有用的metadata的key列表
:arglists doc函数调用时,参数信息
:doc doc函数调用时候,文档信息
:file 源代码
:line 代码当前行数
:macro 如果当前是宏则为真
:name local name
:ns namespace
:tag 期望的返回值或者参数类型
Metadata的read macro: ^#form 和 with-meta 还是不同的,一个是给编译器增加metadata,一个是给数据加的。