如何在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:
- 类型是否需要扩展 Java class 或实现任何接口?是
- 您需要命名类型还是仅需要匿名类型的实例?命名类型
- 您需要能够从 Java 静态引用 class 吗?否
- 您的 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
作为特例。
抱歉,看来 proxy
或 gen-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).
根据我的研究,扩展 Java class 的方法基本上是在命名空间中使用 gen-class 或使用代理。但是看Clojure type selection flowchart,好像提示我可以用record extend a Java class:
- 类型是否需要扩展 Java class 或实现任何接口?是
- 您需要命名类型还是仅需要匿名类型的实例?命名类型
- 您需要能够从 Java 静态引用 class 吗?否
- 您的 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
作为特例。
抱歉,看来 proxy
或 gen-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).