19

假设我有以下代码:

(defn ^{:graph-title "函数 1"} func-1
  [X]
  (用 x 做某事))

(定义获取图形标题
  [功能]
  (字符串
    ((元函数) :graph-title)))

我希望这会返回“函数 1”,但它返回 nil。我认为这源于以下差异,我并不完全理解:

(元 func-1)
=> {:ns some-ns-info, :name func-1}
(元#'func-1)
=> {:ns some-ns-info, :name func-1, :graph-title "功能 1"}

谁可以给我解释一下这个?

4

4 回答 4

35

有关于函数 func-1的元数据、关于Var #'func-1的元数据和关于符号 'func-1的元数据。Clojure 阅读器宏在读取时^将元数据添加到符号。宏在编译时将defn元数据从符号复制到Var 。

在 Clojure 1.2 之前,函数不支持元数据。在 Clojure 1.2 中,它们会这样做,并且还会将一些标准Vardefn元数据复制到函数中:

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上的元数据。

于 2011-04-08T13:57:41.193 回答
21

元数据附加到 var,而不是函数。

因此,要获取图表标题,您必须:graph-title从 var 的元数据中获取条目。你喜欢你的宏吗?

(defmacro get-graph-title
  [func]
  `(:graph-title (meta (var ~func))))

(get-graph-title func-1)
=> "Function 1"
于 2011-04-08T13:21:31.380 回答
3

虽然我不会说这是防弹的,但我会把它放在这里是为了繁荣,以防出于某种原因,你只有 Fn 对象,而不是它的符号或 Var。

据我所知,在defn评估时,它会生成一个名称为 per 的类(munge fn-symbol)。有一个函数demunge会为我们反转这个。因此,从一个 Fn 对象的类名中,我们可以得到符号,从符号中,我们可以找到 var。

(-> (class some-fn)
    (print-str)
    (demunge)
    (symbol)
    (find-var)
    (meta))

有趣的是,demunge可以在clojure.main和中找到clojure.repl,而且它们的作用完全相同,因此请随意要求其中任何一个引入 demunge:

(require '[clojure.main :refer (demunge)])
;; or
(require '[clojure.repl :refer (demunge)])

警告:

正如我之前所说,首先尝试这样做:

(meta #'some-fn)

而不是我在这个答案中显示的,因为它是正确的惯用机制。

于 2020-01-23T09:43:26.817 回答
2

您在源代码中的符号func-1上指定的元数据以 def 特殊形式复制到名为 func-1 的var中。请参阅http://clojure.org/special_forms中的 def 文档

当您评估func-1绑定到 var 的符号的位置时,您会得到 var 的(在这种情况下是函数对象)。见http://clojure.org/vars

函数对象本身不会自动接收在符号/var 上手动指定的元数据。

所以,你想要的信息根本不在函数中。它在 var 中,你必须指定你真的想要 varfunc-1本身而不是它的值。这就是 (var func-1) 和等效的快捷方式 #'func-1 所做的。

于 2011-04-08T13:03:57.170 回答