Clojure 元数据在某些形式上丢失

Clojure metadata lost on certain forms

我对以下表达式的行为差异感到困惑:

(pr (meta ^{:a 0} (list 1 2))) ;; prints nil returns nil

(pr (meta ^{:a 0} '(1 2)));; prints {:line 110, :column 20} returns nil

(pr (meta ^{:a 0} (range 1 3))) ;; prints nil returns nil

(pr (meta ^{:a 0} [1 2])) ;; prints {:a 0} returns nil

这是使用 clojure 1.8.0。我欢迎解释为什么结果不同。

Reader 元数据附加到 reader returns 的形式。在每种情况下,meta 都以该形式在运行时求值的任何值来调用。两者之间没有必要link

如果您需要在运行时将元数据附加到一个值,您可以使用 with-meta 来完成。

让我们看看在问题中列出的每种情况下会发生什么:

  1. (pr (meta ^{:a 0} (list 1 2)))

    Reader 元数据附加到列表结构 (list 1 2),但 meta 不是应用于此列表结构,而是应用于它在运行时计算的值,这将是新分配的两个项目的列表,没有附加元数据。

  2. (pr (meta ^{:a 0} '(1 2)))

    Reader 元数据附加到列表结构 (quote (1 2))(单引号字符是 reader shorthand for (quote …)),但是 meta 不应用于此列表结构,而是应用于它在运行时计算的值,即 reader 在读取此表达式时创建的 (1 2) 列表结构。这带有 {:line … :column …} 元数据,因为 Clojure reader 将其附加到某些类型的表单以用于错误消息等。

  3. (pr (meta ^{:a 0} (range 1 3)))

    同上第一种情况

  4. (pr (meta ^{:a 0} [1 2]))

    这与 '(1 2) 情况非常相似,但关键区别在于,如果非空列表不被视为 function/macro 调用,则需要引用非空列表,而向量则不需要,因此 reader 元数据实际上附加到感兴趣的文字 – 向量 – 本身。

    这也适用于列表:

    (pr (meta ' ^{:a 0} (1 2)))
              ^ note the quote comes before the metadata
    ;; prints {:line 1, :column 14, :a 0}
    

    注意。显式 reader 元数据映射已合并到 reader 自行添加的 {:line … :column …} 映射中。