Clojure中#^{...}和^{...}元数据的区别是什么?

4

请考虑

(defn f ^{:foo "bar"} [x] (* x x))

and

(defn g #^{:foo "bar"} [x] (* x x))

编译和运行都可以。

我有两个问题:首先,为什么(meta f)(meta g)只产生nil?我本来期望它们会产生{:foo "bar"};也就是说,我的元数据定义可能有误吗?

其次,这两种元数据语法有什么区别?第二种看起来像是一个“标记文字”,与edn扩展数据符号有关,但如果没有更多上下文或示例,我无法理解它。

1个回答

8
在Clojure 1.2中,#^元数据读取宏已被替换为^。虽然目前两者没有区别,但旧形式已被弃用,您应该专门使用^
元数据文字应该在要附加到的项之前
(defn ^{:foo "bar"} f [x] (* x x))

还需要记住的一件事是,上述定义中的元数据不是附加在函数上的,而是附加在引用该函数的var上的。您可以使用以下代码获取f var的元数据:

(meta (var f))

或者使用 var 读取宏:

(meta #'f)

感谢您提供的出色答案。我正在查看(doc defn),它说名称应该在元数据之前,除非我误读了文档:"clojure.core/defn([name doc-string? attr-map? [params*] prepost-map? body] [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?])" - Reb.Cabin
1
attr-mapdefn宏的一个特殊功能,旨在使将元数据附加到正在定义的变量更容易。当使用attr-map时,不应该在map前面加上^(defn f {:foo "bar"} [] :baz))。我实际上没有看到过这种用法,使用^读取宏更为常见。我猜attr-map在较早版本的Clojure中很有用,当时处理元数据比较困难,但现在使用^{:foo "bar}形式更符合惯用法,而且更通用(可以放在任何可以保存元数据的对象之前)。 - mtyaka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接