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

欢迎中来!请查阅关于页面以了解更多有关该网站如何运作的信息。

0
Java 互操作

我正在学习 Clojure 并目前正在尝试 Swing 与 Java 的互操作性。我有以下代码段:

(ns test.core
  (:gen-class
   :name Testing
   :extends javax.swing.JFrame
   :init init
   :state state
   :constructors {[String] [String]})
  (:import (javax.swing JFrame)))

(defn -init [x]
      [[x] ()])

因此现在我可以使用 (let [jf (Testing. "example jframe")].. 实例化 JFrame

我在使用 gen-class 中的 :init、:state 和 :constructors 标签上有些迷茫。

1) 在这个例子中我需要使用 :state 吗?据我理解在这里
https://docs.clojure.org/clojure.core/gen-class
以及注释中的 "com.example" 代码,:state 被用来允许对实际上不可变的对象进行更改,通过创建一个新的含有改变状态的对象。但是在上述例子中 JFrame 已经是可变的,所以无论如何都不需要使用 :state。我的这种思考是否正确?

2) :init 是一个函数,它会返回一个包含超类构造函数参数和状态的向量。:constructors 的确切用途是什么?我能够定义一个自定义构造函数,它会像在 Java 中那样调用超类构造函数吗?还是根本不可能,而且我应该在对象初始化后调用一个单独的函数,比如

(let [jf (Testing. "example jframe")]
(doto jf
    (.setSize 200 300)
    (.setVisible true)
    etc..

提前感谢

2 答案

+2

被选中
 
最佳回答

与其走更底层的(但也许功能更丰富)gen-class路线,您可以使用clojure.core/proxy来获得良好的效果。代理允许您定义一个存根类实现,该实现可以继承现有类,调用超类方法实现,重写等,而不需要走genclass所需的AOT编译路线。缺点是它不是那么快(例如,如果您正在代理一个在热点路径上有方法调用的对象,那就可能不太好,需要使用gen-class或其他方法)。实际上,这确实很常见,用于封装Swing组件(甚至 seesaw就是这样做的 )。

我的建议是尝试(如果基于接口)reify | deftype,然后是proxy,然后是gen-class,然后如果更方便或者你愿意,使用Java。我大部分的使用案例都是通过基本的Clojure互操作性处理的,尽管不需要gen-class。

但在这个案例中,jframe已经是可变的,所以根本没有必要使用:state。这种思考对吗?

如果您能够控制JFrame,那么您可以通过互操作性对其进行修改。由于这个类继承自它,因此这是可行的。'state'实现是Clojure特有的实现细节,用于以规范的方式封装您自己的东西(而不是,比如说,一堆单个的实例变量,您通常只需包装一个包含原子和内容的状态映射,以便进行修改)。

或者这根本不可能,我应该在对象初始化后调用一个单独的函数,类似于

您可以将自己的构造函数定义为,并将它们映射到超类构造函数,就像在这个有用的指南中所示。我认为"初始化后"是一个很好的方法,可以限制要放入gen-class中的类特定垃圾。由于您仍然可以通过互操作性操作对象...这是一个可行且常见的选项。

by
非常感谢您的回复。我在我的一个小测试项目中使用seesaw,但一些组件缺失(JDesktopPane,JInternalFrame),因此我不得不深入研究gen-class并感到有点困惑(还阅读了kotka.de指南,它是搜索gen-class时的前三条链接:)
汤姆,现在确实更清晰了,我将研究reify/deftypes。
0
by

您可以使用:constructors定义自己的构造函数,但有一个更好的解决方案是使用Seesaw,它是Swing的优秀Clojure包装器。

https://github.com/daveray/seesaw

...