元数据 #
一、元数据简介 #
元数据是附加在数据上的额外信息,不影响数据本身的相等性判断。元数据常用于类型提示、文档、私有标记等。
1.1 特点 #
- 不影响数据相等性
- 不可变
- 可以附加到大多数数据类型
- 用于编译器优化和文档
1.2 查看元数据 #
clojure
(meta ^:private {:a 1})
(meta ^{:doc "A variable"} #'map)
(meta (with-meta [1 2 3] {:type :vector}))
二、添加元数据 #
2.1 元数据字面量 #
clojure
^{:private true} {:a 1}
^:private {:a 1}
^[String] {:name "test"}
^{:tag String} "hello"
2.2 with-meta #
clojure
(def data (with-meta [1 2 3] {:type :vector :count 3}))
(meta data)
data
2.3 vary-meta #
clojure
(def data [1 2 3])
(def data-with-meta
(vary-meta data assoc :type :vector))
(meta data-with-meta)
2.4 在def中使用 #
clojure
(def ^:private secret "hidden")
(def ^{:doc "A constant" :const true} PI 3.14159)
(meta #'secret)
(meta #'PI)
三、元数据读取 #
3.1 meta #
clojure
(def data (with-meta {:a 1} {:source :test}))
(meta data)
(meta ^:private [1 2 3])
3.2 Var元数据 #
clojure
(defn my-function
"This is a doc string"
[x]
(* x x))
(meta #'my-function)
(:doc (meta #'my-function))
(:arglists (meta #'my-function))
3.3 命名空间元数据 #
clojure
(ns my-ns
{:author "Alice"
:version "1.0.0"})
(meta (find-ns 'my-ns))
四、常用元数据 #
4.1 :private #
clojure
(def ^:private internal-value 42)
(defn ^:private helper []
"internal helper")
4.2 :doc #
clojure
(def ^{:doc "The value of PI"} PI 3.14159)
(defn ^{:doc "Calculate square"} square [x] (* x x))
4.3 :tag (类型提示) #
clojure
(defn ^String process [^String s]
(.toUpperCase s))
(defn add [^Long a ^Long b]
(+ a b))
4.4 :const #
clojure
(def ^:const MAX-VALUE 100)
(def ^:const DEFAULT-TIMEOUT 5000)
4.5 :dynamic #
clojure
(def ^:dynamic *config* {:debug false})
(binding [*config* {:debug true}]
*config*)
4.6 :deprecated #
clojure
(defn ^:deprecated old-function []
"Use new-function instead")
五、元数据与集合 #
5.1 集合元数据 #
clojure
(def data (with-meta [1 2 3] {:type :vector}))
(meta data)
(meta (conj data 4))
(meta (seq data))
5.2 元数据保留 #
clojure
(def data (with-meta {:a 1} {:source :test}))
(meta (assoc data :b 2))
(meta (dissoc data :a))
(meta (into {} data))
5.3 合并元数据 #
clojure
(defn merge-with-meta [m1 m2]
(let [merged (merge m1 m2)
meta1 (meta m1)
meta2 (meta m2)]
(with-meta merged (merge meta1 meta2))))
(def m1 (with-meta {:a 1} {:source :test1}))
(def m2 (with-meta {:b 2} {:source :test2}))
(meta (merge-with-meta m1 m2))
六、元数据与函数 #
6.1 函数元数据 #
clojure
(defn my-function
"Documentation string"
{:added "1.0"
:deprecated "2.0"}
[x]
(* x x))
(meta #'my-function)
6.2 参数元数据 #
clojure
(defn process [^String name ^Long age]
(str name " is " age " years old"))
(meta #'process)
6.3 匿名函数元数据 #
clojure
(def f (with-meta
(fn [x] (* x x))
{:doc "Square function"}))
(meta f)
七、实践示例 #
7.1 验证元数据 #
clojure
(defn with-validation [data validator]
(vary-meta data assoc :validator validator))
(defn validate [data]
(if-let [validator (:validator (meta data))]
(validator data)
true))
(def valid-data
(with-validation
{:name "Alice" :age 30}
#(and (string? (:name %))
(pos? (:age %)))))
(validate valid-data)
7.2 来源追踪 #
clojure
(defn with-source [data source]
(vary-meta data assoc :source source :timestamp (System/currentTimeMillis)))
(defn get-source [data]
(select-keys (meta data) [:source :timestamp]))
(def user-data (with-source {:id 1 :name "Alice"} :api))
(get-source user-data)
7.3 缓存元数据 #
clojure
(defn with-cache-info [data ttl]
(vary-meta data assoc
:cached true
:ttl ttl
:created (System/currentTimeMillis)))
(defn is-cache-valid? [data]
(let [{:keys [cached ttl created]} (meta data)]
(and cached
(< (- (System/currentTimeMillis) created) ttl))))
(def cached-data (with-cache-info {:result "data"} 60000))
(is-cache-valid? cached-data)
7.4 API版本控制 #
clojure
(defn with-api-version [data version]
(vary-meta data assoc :api-version version))
(defn requires-version [data min-version]
(let [version (:api-version (meta data))]
(when (and version (< version min-version))
(throw (ex-info "API version too old"
{:required min-version
:actual version})))))
(def v1-data (with-api-version {:users []} 1))
(requires-version v1-data 1)
八、元数据限制 #
8.1 不支持的类型 #
clojure
(meta 42)
(meta "string")
(meta :keyword)
数字、字符串、关键字等基本类型不支持元数据。
8.2 相等性 #
clojure
(= (with-meta {:a 1} {:x 1})
(with-meta {:a 1} {:x 2}))
元数据不影响相等性判断。
九、元数据工具 #
9.1 查看所有元数据 #
clojure
(defn show-meta [obj]
(let [m (meta obj)]
(when m
(doseq [[k v] m]
(println k "=" v)))))
(show-meta #'map)
9.2 复制元数据 #
clojure
(defn copy-meta [from to]
(with-meta to (meta from)))
(def source (with-meta {:a 1} {:source :test}))
(def target {:b 2})
(meta (copy-meta source target))
十、总结 #
元数据操作速查:
| 操作 | 函数 |
|---|---|
| 添加 | with-meta, ^{:key val} |
| 读取 | meta |
| 修改 | vary-meta |
| 合并 | vary-meta ... merge |
常用元数据键:
| 键 | 用途 |
|---|---|
:private |
私有标记 |
:doc |
文档字符串 |
:tag |
类型提示 |
:const |
常量标记 |
:dynamic |
动态变量 |
:deprecated |
废弃标记 |
关键点:
- 元数据不影响数据相等性
- 用于类型提示、文档、标记
- 大多数集合类型支持元数据
with-meta添加,meta读取vary-meta基于现有元数据修改
下一步,让我们学习状态与标识!
最后更新:2026-03-27