当函数 returns 是它的符号时,如何从 var 中提取元数据?

How do I extract metadata from a var when a function returns its symbol?

我正在使用 re-frame with spec to validate app-db, much like in the todomvc 示例。

当用户输入无效时,我使用 s/explain-data(在重新框架拦截器中)到 return 一个 problems 映射命名 :pred icate 导致验证失败。这个谓词是一个像 project.db/validation-function.

这样的符号

我的验证函数有元数据,可以使用以下方法从 repl 访问:

(meta #'project.db/validation-function)

函数定义(在 project.db 命名空间中)如下所示:

(defn validation-function
  "docstring..."
  {:error-message "error message"}
  [param]
  (function-body...)

问题是我不知道如何动态检索元数据(在 project.events 命名空间中工作),例如:

(let [explain-data (s/explain-data spec db)
      pred (->> (:cljs.spec.alpha/problems explain-data) first :pred)
      msg (what-goes-here? pred)]
  msg)

我尝试了以下方法来代替 what-goes-here?

我认为问题在于我得到了一个符号,但我需要它所指的 var,这是元数据所在的位置。

我试过使用宏,但我真的不知道我在做什么。 是我能找到的最接近的讨论,但我无法解决。

求助!

编辑:抱歉,我没有看到 var 对你不起作用。仍在努力中...

您需要用 var 将符号 project.db/validation-function 括起来。这会将符号解析为 var.

所以what-goes-here?应该是

(defn what-goes-here? [pred]
  (var pred))

一般来说,您不能这样做,因为变量在 ClojureScript 中没有具体化。

来自 https://clojurescript.org/about/differences#_special_forms :

  • var notes
    • Vars are not reified at runtime. When the compiler encounters the var special form it emits a Var instance reflecting compile time metadata. (This satisfies many common static use cases.)

在 REPL,当你评估

(meta #'project.db/validation-function)

这与

相同
(meta (var project.db/validation-function))

并且在编译 (var project.db/validation-function) 时,会发出 JavaScript 代码以创建一个 cljs.core/Var 实例,其中包含您可以使用 meta.如果你很好奇,相关的analyzer and compiler代码很有启发性。

因此,如果 (var project.db/validation-function)(或 reader 等价物 #'project.db/validation-function)在您的源代码中的任何地方都不存在(或间接通过使用类似 ns-publics) 此数据在运行时不可用。

在优化代码大小时,省略 var 具体化是一件好事。如果启用 :repl-verbose REPL 选项,您将看到表达式 (var project.db/validation-function) 发出大量 JavaScript 代码。

当在 REPL 中使用 defs 时,编译器携带足够的分析元数据,并且事情已经完成——比如对 def 形式的评估 return var 而不是value——以构建你正在使用具体化的 Clojure 变量的幻觉的名义。但在为生产交付生成代码时,这种错觉有意消失,只保留基本的运行时行为。