当函数 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?
:
symbol?
给出 true
str
给出 "project.db/validation-function"
meta
给出 nil
var
给出编译时错误 "Unable to resolve var: p1__46744# in this context"
我认为问题在于我得到了一个符号,但我需要它所指的 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 中使用 def
s 时,编译器携带足够的分析元数据,并且事情已经完成——比如对 def
形式的评估 return var 而不是value——以构建你正在使用具体化的 Clojure 变量的幻觉的名义。但在为生产交付生成代码时,这种错觉有意消失,只保留基本的运行时行为。
我正在使用 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?
:
symbol?
给出true
str
给出"project.db/validation-function"
meta
给出nil
var
给出编译时错误 "Unable to resolve var: p1__46744# in this context"
我认为问题在于我得到了一个符号,但我需要它所指的 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 中使用 def
s 时,编译器携带足够的分析元数据,并且事情已经完成——比如对 def
形式的评估 return var 而不是value——以构建你正在使用具体化的 Clojure 变量的幻觉的名义。但在为生产交付生成代码时,这种错觉有意消失,只保留基本的运行时行为。