如何在Clojure 中使用defrecord 来扩展Java class?

How to use defrecord in Clojure to extend a Java class?

根据我的研究,扩展 Java class 的方法基本上是在命名空间中使用 gen-class 或使用代理。但是看Clojure type selection flowchart,好像提示我可以用record extend a Java class:

  1. 类型是否需要扩展 Java class 或实现任何接口?是
  2. 您需要命名类型还是仅需要匿名类型的实例?命名类型
  3. 您需要能够从 Java 静态引用 class 吗?否
  4. 您的 class 是否对域值建模 - 从而受益于类似 hasmap 的功能和语义学?是

使用defrecord

所以问题是……怎么做?

例如(来自):

public final class Second extends Struct {
    public final Signed32 a_number = new Signed32();
    public Second(final Runtime runtime) {
        super(runtime);
    }
}

public final class Top extends Struct {              
    public final Second second = inner(new Second(getRuntime()));  
    public final Second[] seconds = array(new Second[5]);
    public final Signed32 another_number = new Signed32();
    public final Signed32[] more_numbers = array(new Signed32[5]);
    public Top(final Runtime runtime) {
        super(runtime);
    }
}

我...

(defrecord Second)
(extend jnr.ffi.Struct
        Second)

?

我认为流程图是错误的。查看 Clojure - Datatypes: deftype, defrecord and reify 文档我们可以看到:

  • a deftype/defrecord can implement one or more protocols and/or interfaces

没有提到扩展现有 class。事实上,查看 the documentation for defrecord itself 没有提到扩展现有的 classes,除了 Object 作为特例。

抱歉,看来 proxygen-class 是您唯一的选择。

为什么需要命名类型?如果,如您所说,您不需要从 Java 静态引用它,我看不出有任何特别的理由来命名该类型。如果您正确回答了该问题,它会将您带到 proxy。您的问题是您选择了不一致的答案:您说您需要一个命名的 class,但对于您可能需要一个的任何原因都没有回答是。考虑流程图的原因是 Java 代码可能希望按名称引用您的代码,在这种情况下 gen-class。但是,一方面说您必须扩展 Java class,另一方面说您的新类型将是一个简单的数据载体,为域值建模是没有意义的。 Clojure 记录在这方面做得很好,但是拥有一个来自 Java 的令人讨厌的可变基础 class 并不能成为一个好的域对象。

就是说,如果您对“对域类型建模”的回答是“否”,它会将您带到 deftype,它也无法扩展 class。我认为如果你想扩展 class 它允许你逃离“互操作区”是一个错误:最好将接口和子 classing 分开,但是流程图可以就这么大。

FWIW comments on the original flowchart post 包括你的问题,作者的回答,回应了我使用 proxy 的建议和流程图已经足够大的问题:

That first decision isn’t exclusively indicating that you need to extend a class — it includes implementing interfaces. So, there is a bit of ambiguity there. Of course, you’re in gen-class-land there, but breaking things out more to eliminate the ambiguity would make the flowchart a fair bit bigger, I think.

FWIW, I’d personally drop the named type requirement there, use proxy, and just def the result of (class (create-proxy-instance …)) for instance? checks and such (assuming that that’s why you need the named type).