我有这种情况:
(defn a []
(do-something))
(defn b []
(let [original (a)]
(modify-original)))
(defn c []
(binding a b)
(a))
如何“破解绑定”并在a
中呼叫b
?我认为闭包可以处理这种情况所以我写了类似的东西,但它不起作用:
(defn c []
(let [original-a a
b (fn []
(let [original (original-a)]
(modify-original)))]
(b)))
哦,我差点忘了:代码要复杂得多,因为c
没有直接调用b
。它被称为它的子功能,我无法改变。这就是为什么我不能使用类似的东西:
(defn ^:dynamic state [] (something))
答案 0 :(得分:4)
如果您希望始终使用函数a
中b
的原始值,则可以将原始a
“抓取”到函数b
的环境中(闭包) ):
(defn ^:dynamic a []
(do-something))
(def b (let [a a]
(fn []
(let [original (a)]
(modify-original)))))
(defn c []
(binding [a b]
(a)))
<强>更新即可。或
(let [a a] (defn b []
(let [original (a)]
(modify-original))))
答案 1 :(得分:1)
你可以使用java线程来“透视”绑定,方法是创建并从未绑定的线程中获取var的值,并将其保留在var / atom /中ref / etc由它所绑定的线程上的代码找到:
user> (defn c []
(let [tmp-atom (atom nil)
original-a (do (doto (Thread. #(reset! tmp-atom a)) .start .join)
@tmp-atom)]
{:local-a a :original-a original-a}))
user> (c)
{:local-a 4, :original-a 4}
user> (binding [a 7] (c))
{:local-a 7, :original-a 4}
或者对于较小的示例,首先定义一些共享状态和一个要绑定的var
user> (def result (atom ""))
#'user/result
user> (def ^:dynamic a 4)
#'user/a
在没有绑定的线程上捕获a,它将获得a:
的根值user> (binding [a 5] (.start (Thread. #(reset! result (str "a was " a)))))
#<Thread Thread[Thread-77,5,main]>
user> result
#<Atom@7c75031f: "a was 4">
然后将其与运行相同代码进行比较,而不使用使用a的绑定值的线程:
user> (binding [a 5] (reset! result (str "a was " a)))
"a was 5"
user> result
#<Atom@7c75031f: "a was 5">
user>
大多数(全部?)正常的Clojure并发工具都小心地将绑定推送到新线程以防止这样的情况
<小时/> 把它们放在一起: