2024 Clojure 状态调查!中分享您的想法。

欢迎!请参阅关于页面获取更多关于这一机制的信息。

0投票
Java 互操作
  (deftype l [^java.util.List x])
  (use '[clojure.reflect :as r])
  (:members (r/reflect (l. `())))

尽管有 java.util.List 的类型提示,但在反射中 x 总是看起来像 Object

我一直在尝试在 100% Clojure 中使一个 optaplanner 示例工作 https://github.com/joinr/optaplanner-clj/tree/163d326a6433b88ca9811e33d30758ceff42b91f。代码正在执行,但在运行 (solve (->problem)) 时出现此错误。

  1. 未处理的 java.lang.IllegalStateException: The solutionClass (class optaplanner_clj.data.TimeTable) 包含一个被注解为 PlanningEntityCollectionProperty 的成员(public final java.lang.Object optaplanner_clj.data.TimeTable.lessonList),它不返回 Collection 或数组
    PlanningEntityCollectionProperty
    java.lang.Object optaplanner_clj.data.TimeTable.lessonList)
    不返回 Collection 或数组。

2 答案

0投票

其他人可能在这里能更权威地回答,但我觉得 Clojure 编译器为 Clojure 函数和 deftype 方法创建的方法,参数类型和返回类型可以是三种之一:java.lang.Object,原始 long 或原始 double。如果不是这些类型,您最有效的选择可能是使用除 Clojure 编译器之外的其他方式创建 JVM 字节码,例如编写一些 Java 包装代码并用 javac 编译,或者学习一些生成 JVM 字节码的库,像 Clojure 库使用的 asm 库。

这是正确的。如果您需要一个具有特定类型的类,您需要创建一个具有特定类型的接口,然后让deftype实现该接口。
这里的问题是optaplanner强制进行大量注解,并在其验证阶段特别反映在类的注解字段上。如果没有类型(deftype强制为对象),则optaplanner会崩溃。即使提供了具有getters和setters的接口也是如此。在字段上发生反射。尽管我们还有一些其他解决方法,但看来完全遵守optaplanner互操作性需要自定义类定义(例如使用insn库)或修改deftype产生的输出。
0投票

供参考,clojure.tools.emitter.jvm 似乎确实保留了非原始字段的类型...

 (require '[clojure.tools.emitter.jvm :as e])

(e/eval '(deftype blah [^String x]) {:debug? true})
;;;
// class version 50.0 (50)
// access flags 0x31
public final class user/blah implements clojure/lang/IType  {

  // compiled from: user/blah

  // access flags 0x11
  public final Ljava/lang/String; x
...

user> (require '[clojure.reflect :as r])
nil
user> (r/reflect (user.blah. "hello"))
{:bases #{java.lang.Object clojure.lang.IType},
 :flags #{:public :final},
 :members
 #{{:name getBasis,
    :return-type clojure.lang.IPersistentVector,
    :declaring-class user.blah,
    :parameter-types [],
    :exception-types [],
    :flags #{:public :static}}
   {:name user.blah,
    :declaring-class user.blah,
    :parameter-types [java.lang.Object],
    :exception-types [],
    :flags #{:public}}
   {:name x,
    :type java.lang.String,  ;;in clojure
    :declaring-class user.blah,
    :flags #{:public :final}}}}
...