本文共 1999 字,大约阅读时间需要 6 分钟。
动态类型语言,少了静态类型语言必须声明变量类型的累赘,但也缺失了编译时类型检查和编译时优化的好处。cljs虽然作为动态类型语言,但其提供Metadata让我们在必要的时候可选择地补充类型提示,以便提高代码可读性和供编译器优化使用。除了上述以外,Metadata还让我们在不影响对象本质的前提下,附加额外信息增强元编程能力。
首先要明确一点的是,Metadata不是任何对象/值都拥有的。只有如下的对象才可附加Metadata
meta
读取Metadata 通过meta
我们可以获取对象的Metadata,若没有则返回nil
。
(def a 1)(meta #'a);;=> {:ns cljs.user, :name a, :file "", :end-column 7, :source "a", :column 1, :line 1, :end-line 1, :arglists (), :doc nil, :test nil}
上述示例1中是(meta #'a)
而不是(meta a)
,前者是获取Var的Metadata,而后者是获取值1的Metadata,显然后者是没有Metadata的。
(def a (with-meta 'a {:something "test"}))(meta a);;=> {:something "test"}
通过with-meta
我们可以获取附加了metadata的symbol'a
(注意作为入参的symbol'a
不会受到影响)。
with-meta
后期追加Metadata 上面我们已经看到with-meta
的使用示例了,下面我们再看看具体的函数签名吧。
;; Returns an object of the same type and value as obj, with map m as its metadata.(with-meta obj m)
值得注意的是,with-meta
会的返回值才会附加上metadata,而入参obj不会附加上metadata。因此需要用绑定来保存结果,以便后续使用。
(def a (with-meta obj m))
除了with-meta
后期追加外,很多时候我们是在定义时就已经可以明确metadata的了,那么可以两种形式定义metadata。
;; 定义Var的metadata(def ^{:dynamic true, :tag "test"} a 1);; 读取metadata(meta #'a);; 定义Map的metadata(def b ^{:something "test"} {:name 1});; 读取metadata(meta b)
有时我们只想定义一两个metadata,完整写法显然有些累赘,那么我们就可以采用metadata reader的写法,小清新一下。
(def ^:dynamic ^"test" a 1);;等价于(def ^{:dynamic true, :tag "test"} a 1)
缩写是有限制,所以只能表达如下metadata
^:foo ;;=> ^{:foo true}^"foo";;=> ^{:tag "foo"}^foo ;;=> ^{:tag}
&esmp;至于其它metadata则还是要使用完整写法处理。
:dynamic ;; Boolean, 指定Var为动态绑定:private ;; Boolean, 指定该Symbol的访问控制为私有,默认为public:doc ;; String, 设置document string:test ;; Function,不带入参的函数,单元测试函数:tag ;; Class,指定Symbol所指向的Var的数据类型
另外编译器会自动附加一下信息到Var上。
:file ;; String:line ;; Int:name ;; Symbol:ns ;; Symbol:macro ;; Boolean,true表示是macro:arglists ;; List,每个Vector表示一个函数签名
今天就写到这里,下次继续^_^
尊重原创,转载请注明来自: ^_^肥仔John