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:solutionClass (class optaplanner_clj.data.TimeTable) 有一个
    带有 PlanningEntityCollectionProperty 注解的成员 (public final
    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强制为object),那么optaplanner会崩溃。 即使提供了getter和setter的接口。 反射发生在字段上。 我们虽然得到了其他注解jank的运行,但看起来完全遵循optaplanner互操作性需要自定义类定义(例如,使用insn库),或者改变了deftype输出的内容。
0
by

为了参考,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}}}}
...