2024 Clojure 状态调查中分享您的想法!

欢迎!请访问关于页面,了解更多关于如何使用本网站的信息。

+1
ClojureScript
(def foo "foo")
(meta (var foo))
;=> {:ns cljs.user, :name foo, :file "<cljs repl>", :end-column 9, :source "foo", :column 1, :line 1, :end-line 1, :arglists (), :doc nil, :test nil}
(alter-meta! (var foo) assoc :foo 42)
(meta (var foo))
;{:ns cljs.user, :name foo, :file "<cljs repl>", :end-column 9, :source "foo", :column 1, :line 1, :end-line 1, :arglists (), :doc nil, :test nil}

此问题:[链接 http://dev.clojure.org/jira/browse/CLJS-1248](http://dev.clojure.org/jira/browse/CLJS-1248),已修复 vary-meta,但未在原地修改元数据。

5 答案

0

评论者:baritonehands

嗯,我已经克隆了,但它不允许我编辑。

所以 alter-meta! 的文档说明它支持 Vars

"原子性地设置 namespace/var/ref/agent/atom 的元数据为

(apply f its-current-meta args)

f 必须没有副作用"

但实际上它不起作用,并且查看源代码后,支持 Vars 所需的只是从 _meta 中删除下划线

(defn alter-meta!
(link: iref f & args)
(set! (.-meta iref) (apply f (.-meta iref) args)))

(deftype Var (link: val sym meta)
...
IMeta
(-meta (link:
) _meta)
...

0

评论者:baritonehands

进一步实验后发现,Vars 的表现不符合我的预期。每次引用 var(使用(var)或使用 #')时,编译器都会创建一个新的 var/metadata 实例,因此对先前的修改不会反映出来。

然而,当我将变量存储在不同的变量中时,它又是如何工作的。

例如

(set! js/window.lhs #'foo)
(set! js/window.rhs #'foo)

在JS控制台,lhs !== rhs。但如果你这样做

(set! js/window.lhs #'foo)
(set! js/window.rhs js/window.rhs)

那么JS控制台会显示lhs === rhs为真。

所以我猜我必须将变量引用存储在另一个def中,以便按预期操作它吗?

0
by

评论者:thheller

CLJS不使用变量进行运行时操作,不能像这样进行修改。{{cljs.core/Var}}实例是根据该变量的{{cljs.analyzer}}数据创建的,该数据在CLJ侧上,因此无法直接修改,除非通过宏。如果你在创建实例后传递变量实例,则它将正常工作,但{{cljs.core/var}}无论如何都会创建一个新的实例。

0
by

评论者:baritonehands

是的,我在尝试了几小时之后意识到了这一点。

那么,能否更新alter-meta!文档以删除对变量的提及?此外,最好在var的docstring中指出它的行为与Clojure变量不同。

0
by
参考: https://clojure.atlassian.net/browse/CLJS-2970 (由 alex+import 报告)
...