我对以下表达式的行为差异感到困惑:
(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。我欢迎解释为什么结果不同。
答案 0 :(得分:5)
阅读器元数据附加到阅读器返回的表单。在每种情况下,meta
都是以运行时评估的形式调用的。一个与另一个之间没有必要的联系。
如果需要在运行时将元数据附加到值,可以使用with-meta
来执行此操作。
让我们看一下问题中列出的每种情况会发生什么:
(pr (meta ^{:a 0} (list 1 2)))
Reader元数据附加到列表结构(list 1 2)
,但meta
不应用于此列表结构,而是应用于它在运行时评估的值,这将是新分配的两个列表没有附加元数据的项目。
(pr (meta ^{:a 0} '(1 2)))
Reader元数据附加到列表结构(quote (1 2))
(单引号字符是(quote …)
的读者简写),但meta
不应用于此列表结构,而是应用于值它在运行时求值,这是读者在读取此表达式时创建的(1 2)
列表结构。这带有{:line … :column …}
元数据,因为Clojure读者将其附加到某些类型的表单以用于错误消息等。
(pr (meta ^{:a 0} (range 1 3)))
与上述第一个案例相同。
(pr (meta ^{:a 0} [1 2]))
这与'(1 2)
情况非常相似,但关键的区别在于,如果非空列表不被视为函数/宏调用,则需要引用,而向量则不需要,因此读者元数据实际上附加到感兴趣的文字 - 矢量 - 本身。
这也适用于列表:
(pr (meta ' ^{:a 0} (1 2)))
^ note the quote comes before the metadata
;; prints {:line 1, :column 14, :a 0}
NB。显式读者元数据地图已合并到读者自己添加的{:line … :column …}
地图中。