2024 Year of 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 修复了 vary-meta,但没有就地修改元数据。

5 个答案

0

评论者:baritonehands

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

因此 alter-meta! 的文档指出该函数支持 Vars

"原子地设置名称空间/变量/ref/代理/原子的元数据为

(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 创建一个新的实例,所以对前一个实例所做的任何修改都不会反映出来。

然而,当我把 var 存储在不同的 var 中时,它却可以正常工作。

例如

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

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

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

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

所以我觉得我必须将变量引用存储在另一个定义中,以便按照预期进行操作?

0

评论者:thheller

CLJS 不在运行时使用 vars,并且无法如这样进行修改。{{cljs.core/Var}} 实例是从那个 var 的 {{cljs.analyzer}} 数据创建的,这个 var 存活在 CLJ 一侧,因此不能直接从 CLJS 进行修改,除非通过宏。传递创建后的 var 实例时它确实会工作,但是 {{cljs.core/var}} 总是会创建一个新的实例。

0

评论者:baritonehands

几小时试验错误后我意识到了这一点。

所以 could the alter-meta! 文档被更新以删除对 vars 的提及?并且,如果 var 的文档字符串指出其行为与 Clojure vars 不同,那会很棒。

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