【问题标题】:Change the value of a Clojure var without touching the metadata在不接触元数据的情况下更改 Clojure var 的值
【发布时间】:2021-05-31 16:26:28
【问题描述】:

我一直在假设 var 的元数据是“稳定的”,也就是说,我可以在不更改 var 元数据的情况下更改 var 的值。现在我发现我的理解有问题。代码:

(def ^{:Metadata "metaA"} A 1)  ;; Define A with value 1 and metadata.
=> #'thic.core/A
(def ^{:Metadata "metaB"} B 2)  ;; Define B with value 2 and metadata.
=> #'thic.core/B
A                               ;; A's value is 1.
=> 1
B                               ;; B's value is 2.
=> 2
(meta (var A))
=>
{:Metadata "metaA",             ;; A has the defined metadata.
 :line 1,
 :column 1,
 :file "C:\\Users\\Joe User\\AppData\\Local\\Temp\\form-init2487748963910096550.clj",
 :name A,
 :ns #object[clojure.lang.Namespace 0x147c445 "thic.core"]}
(meta (var B))
=>
{:Metadata "metaB",             ;; So does B.
 :line 1,
 :column 1,
 :file "C:\\Users\\Joe User\\AppData\\Local\\Temp\\form-init2487748963910096550.clj",
 :name B,
 :ns #object[clojure.lang.Namespace 0x147c445 "thic.core"]}
(def B A)                       ;; Give B A's value,
=> #'thic.core/B
A
=> 1
B                               ;; which it now has,
=> 1
(meta (var B))                  ;; and B's previously-defined metadata is gone.
=>
{:line 1,
 :column 1,
 :file "C:\\Users\\Joe User\\AppData\\Local\\Temp\\form-init2487748963910096550.clj",
 :name B,
 :ns #object[clojure.lang.Namespace 0x147c445 "thic.core"]}
(meta (var A))                  ;; A's remains unchanged.
=>
{:Metadata "metaA",
 :line 1,
 :column 1,
 :file "C:\\Users\\Joe User\\AppData\\Local\\Temp\\form-init2487748963910096550.clj",
 :name A,
 :ns #object[clojure.lang.Namespace 0x147c445 "thic.core"]}

有没有一种方法可以在不清除 B 中的元数据的情况下将 A 的值分配给 B?
或者我只是不明白“绑定”和“赋值”之间的区别?
Clojure in Action 第 2 版说“当从具有元数据的值创建新值时,元数据是复制到新数据中。” (p. 57) 我的例子不是创造一个新的价值。那是问题吗?我仍然想修改 var 的值而不修改其元数据。
ClojureGods,我谦卑地恳求你。

【问题讨论】:

  • 能否请您详细说明为什么需要使用def 重新定义变量。用例是什么?。这在 clojure 中看起来真的很单调。尽管alter-var-root 会这样做,但也许还有更好的方法来实现您想要的功能。
  • leetwinski:如果有任何其他方法可以做到这一点不会改变元数据,我不会嫁给'def'来更改 var 的值。这只是我对 Clojure 的有限知识告诉我它是如何完成的唯一方法。感谢您的建议和您的兴趣。

标签: clojure metadata


【解决方案1】:

alter-var-root 可以做到。

-------------------------
clojure.core/alter-var-root
([v f & args])
  Atomically alters the root binding of var v by applying f to its
  current value plus any args

例如:

; Clojure 1.10.3
(def ^{:Metadata "metaA"} A 1)
; #'user/A
(def ^{:Metadata "metaB"} B 2)
; #'user/B
A
; 1
B
; 2
(meta #'A)
; {:Metadata "metaA", :line 1, :column 1, :file "NO_SOURCE_PATH", :name A, :ns #object[clojure.lang.Namespace 0x2189e7a7 "user"]}
(meta #'B)
; {:Metadata "metaB", :line 1, :column 1, :file "NO_SOURCE_PATH", :name B, :ns #object[clojure.lang.Namespace 0x2189e7a7 "user"]}
(alter-var-root #'B (constantly A))
; 1
B
; 1
(meta #'B)
; {:Metadata "metaB", :line 1, :column 1, :file "NO_SOURCE_PATH", :name B, :ns #object[clojure.lang.Namespace 0x2189e7a7 "user"]}

【讨论】:

  • 谢谢你,cfrick。有 6 本书,只有 2 本书提到了这个内在,显然我不应该改变 var 的根值。 Clojure 是一种“完全不同”的编程语言,最终我会习惯并擅长它。
  • @LionelGoulet 如果你在野外看到这个,它很可能是围绕“开发工具”。例如。一些user.clj 用于重新加载系统或真正替换某些东西以进行开发或测试。假设后者是你所追求的……
猜你喜欢
  • 2015-01-06
  • 1970-01-01
  • 2014-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多