3

我有这样的情况:

 (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))

4

2 回答 2

4

如果您想始终使用您提到的ain 函数的原始值,您可以将原始值“抓取”到函数(闭包)的环境中:bab

(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))))
于 2013-01-31T16:37:21.313 回答
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 并发工具都会小心地将绑定推送到新线程以防止出现这种情况


把它放在一起:

于 2013-01-31T18:46:09.750 回答