说我有以下代码:
(defn ^{:graph-title "Function 1"} func-1 [x] (do-something-with x)) (defn get-graph-title [func] (str ((meta func) :graph-title)))
我希望这会返回“Function 1”,但它会返回nil。我认为这源于以下差异,我不完全理解:
(meta func-1) => {:ns some-ns-info, :name func-1} (meta #'func-1) => {:ns some-ns-info, :name func-1, :graph-title "Function 1"}
有人可以向我解释一下吗?
答案 0 :(得分:31)
功能 func-1
上的元数据, Var #'func-1
上的元数据以及符号上的元数据 'func-1
。 Clojure阅读器宏^
在读取时将元数据添加到符号。 defn
宏在编译时将元数据从符号复制到 Var 。
在Clojure 1.2之前,函数不支持元数据。在Clojure 1.2中,他们这样做了,defn
还将一些标准 Var 元数据复制到函数:
Clojure 1.2.0
user=> (defn ^{:foo :bar} func-1 [] nil)
#'user/func-1
user=> (meta func-1)
{:ns #<Namespace user>, :name func-1}
user=> (meta #'func-1)
{:foo :bar, :ns #<Namespace user>, :name func-1, ...
但是,在当前的Clojure 1.3快照中,defn
不会将任何元数据复制到该函数中:
Clojure 1.3.0-master-SNAPSHOT
user=> (defn ^{:foo :bar} func-1 [] nil)
#'user/func-1
user=> (meta func-1)
nil
user=> (meta #'func-1)
{:foo :bar, :ns #<Namespace user>, :name func-1, ...
通常,如果要获取定义的元数据,则需要 Var 上的元数据。
答案 1 :(得分:19)
元数据附加到var,而不附加到函数。
因此,要获得图表标题,您必须从var的元数据中获取条目:graph-title
。你觉得你的宏怎么样?
(defmacro get-graph-title
[func]
`(:graph-title (meta (var ~func))))
(get-graph-title func-1)
=> "Function 1"
答案 2 :(得分:2)
您在源代码中的符号 func-1上指定的元数据将被def特殊形式复制到名为func-1的 var 。请参阅http://clojure.org/special_forms
中的def文档当你评估func-1
这是一个与var绑定的符号时,你会得到var的值(在这种情况下是函数对象)。见http://clojure.org/vars
函数对象本身不会自动接收符号/ var。
上手动指定的元数据因此,您想要的信息根本不在函数中。它在var中,你必须指定你真的想要var func-1
本身而不是它的值。这就是(var func-1)和等效的快捷方式#'func-1。
答案 3 :(得分:0)
虽然我不会说这是防弹的,但为了繁荣起见,我将其放在此处,以防万一出于某种原因,您只有Fn对象,而没有符号或Var。
据我所知,当defn
求值时,它将生成一个名称为(munge fn-symbol)
的类。有一个名为demunge
的函数将为我们反向执行此操作。因此,从Fn对象的类名称中,我们可以找回符号,从符号中,我们可以找到var。
(-> (class some-fn)
(print-str)
(demunge)
(symbol)
(find-var)
(meta))
很有趣的是,demunge
和clojure.main
中都可以找到clojure.repl
,它们的作用完全相同,因此,请要求其中的任何一个都带进去: / p>
(require '[clojure.main :refer (demunge)])
;; or
(require '[clojure.repl :refer (demunge)])
警告:
就像我之前说的,首先尝试做:
(meta #'some-fn)
与其说的是我的回答,不如说是因为它是适当的惯用机制。