在《2024 年 Clojure 调查报告》中分享您的想法!(点击这里参与调查)

欢迎!请参阅“关于”页面了解有关此功能的一些更多信息。

0
编译器

在评估或编译 clojure.lang.IType 实现时,编译器会尝试反射性地访问其字段。如果字段被标记为可变(即私有),则会导致错误。

`
Clojure 1.9.0-master-SNAPSHOT
user=> (deftype T [^:unsynchronized-mutable t])
user.T
user=> (T. :t)

object[user.T 0x2654635 "user.T@2654635"]

user=> (eval (T. :t))
CompilerException java.lang.IllegalArgumentException: 在类 user.T 中找不到匹配的字段:t

        Reflector.java:  271  clojure.lang.Reflector/getInstanceField
         Compiler.java: 4724  clojure.lang.Compiler$ObjExpr/emitValue
         Compiler.java: 4851  clojure.lang.Compiler$ObjExpr/emitConstants
         Compiler.java: 4529  clojure.lang.Compiler$ObjExpr/compile
         Compiler.java: 4049  clojure.lang.Compiler$FnExpr/parse
         Compiler.java: 6866  clojure.lang.Compiler/analyzeSeq
         Compiler.java: 6669  clojure.lang.Compiler/analyze
         Compiler.java: 6924  clojure.lang.Compiler/eval
         Compiler.java: 6890  clojure.lang.Compiler/eval
              core.clj: 3105  clojure.core/eval

...
`

对于不实现 IType 的类,不存在此类问题。

`
user> (deftype* user/U user.U)

    [^:unsynchronized-mutable u]
    :implements [])

nil
user> (eval (user.U. :u))

object[user.U 0x34699051 "user.U@34699051"]

`

此问题通常发生在实现带有缓存的散列的 tagged literal 的 deftype 时。

2 个答案

0

评论人:alexmiller

是的,这很有趣。编译器将 deftype 编译成一个调用构造函数的调用,该调用使用字段当前的字段值,但是无法访问可变字段。一个替代方案是提供一个标准方法来"读取"字段集,而不是依赖反射。(另一个是更改可变字段的访问修饰符,但是我认为这是不可能的。)

0
参考文献:https://clojure.atlassian.net/browse/CLJ-2092(由 bendlas 报告)
...