【问题标题】:How to call original function when it's shadowed by binding?被绑定遮蔽时如何调用原始函数?
【发布时间】:2013-02-01 03:47:26
【问题描述】:

我有这样的情况:

 (defn a []
   (do-something))

 (defn b []
   (let [original (a)]
      (modify-original)))

 (defn c []
   (binding a b)
     (a))

如何“打破绑定”并在b 中调用a?我认为闭包可以处理这种情况,所以我写了一些与此类似的东西,但它不起作用:

 (defn c []
   (let [original-a a
         b (fn [] 
             (let [original (original-a)]
               (modify-original)))]
     (b)))

哦,我差点忘了:代码要复杂得多,因为c 不直接调用b。它在它的子函数中被调用,我无法更改。这就是为什么我不能使用类似的东西:

(defn ^:dynamic state [] (something))

【问题讨论】:

  • 为了让它工作,我认为“a”应该被声明为动态的。如果您真的想调用“a”的根值,那么为什么不能在绑定表单之前将a的值复制到另一个var,然后调用它。还是我想念您的用例?

标签: clojure functional-programming


【解决方案1】:

如果您想始终在函数 b 中使用 a 的原始值,您可以将原始 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))))

【讨论】:

  • 好的,但是如果我无法更改 a 怎么办?这是一个库函数。
  • @AdamSznajder 我没有改变a。还是您的意思是^:dynamic 部分?没有这个你不能bind新值。
【解决方案2】:

您可以使用 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 并发工具都会小心地将绑定推送到新线程以防止出现这种情况


把它放在一起:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    相关资源
    最近更新 更多