修复 - “无法分配给非可变”编译错误

时间:2017-01-17 10:13:11

标签: android clojure

我将clj-1472-2描述的here应用于clojure 1.8,但是当我使用这个修补版本的clojure来构建依赖于core.async的库时,编译失败了:

java.lang.IllegalArgumentException: Cannot assign to non-mutable: value, compiling:(clojure/core/memoize.clj:58:7)
Exception in thread "main" java.lang.IllegalArgumentException: Cannot assign to non-mutable: value, compiling:(clojure/core/memoize.clj:58:7)

由于对锁定宏的修补更改,在RetryingDelay(memoize.clj)中会发生这种情况:

(deftype RetryingDelay [fun ^:volatile-mutable available? ^:volatile-mutable value]
  clojure.lang.IDeref
  (deref [this]
    ;; first check (safe with volatile flag)
    (if available?
      value
      (locking fun
        ;; second check (race condition with locking)
        (if available?
          value
          (do
            ;; fun may throw - will retry on next deref
            (let [v (fun)]
              ;; this ordering is important - MUST set value before setting available?
              ;; or you have a race with the first check above
              (set! value v)
              (set! available? true)
              v)))))))

在补丁后锁定宏:

(defmacro locking
  "Executes exprs in an implicit do, while holding the monitor of x.
  Will release the monitor of x in all circumstances."
  {:added "1.0"}
  [x & body]
  `(let [lockee# ~x]
     (clojure.lang.Util/lock lockee# (^{:once true} fn* [] ~@body))))

Util / lock是:

static public Object lock(final Object lockee, final IFn f) {
    synchronized(lockee) {
        return f.invoke();
    }
}

为什么会出现此错误?

解决它会有什么适当的改变?

更新

我应该提到,尝试构建修补版本的clojure的原因是能够在Android上运行用clojure编写的jar(Lollipop及更高版本)作为java应用程序的一部分(不是clojure中的完整应用程序) ),CLJ-1472提供了更多信息。

1 个答案:

答案 0 :(得分:0)

我认为这是因为locking宏将locking的正文放入fn并且fn内部public class RetryingDelay implements clojure.lang.IDeref { private final IFn fun; private volatile boolean available; private volatile Object value; public RetryingDelay(IFn fun) { this.fun = fun; } public Object deref() { if(available) { return value; } else { synchronized(fun) { if(available) { return value; } else { Object v = fun.invoke(); value = v; available = true; return v; } } } } } 您无权访问{{1}}的可变字段外部定义范围。

实现像这样的低级别的东西最简单的方法就是用Java编写,而不是用Clojure编写(这样你也不需要依赖一个未应用的补丁)。

像这样(我没有尝试编译它,所以这可能有小错误):

{{1}}