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的句柄,那么您就可以通过互操作性对它进行更新。由于这个类是由它继承的,因此这是可能的。"状态"实现是Clojure特有的实现细节,用于以传统方式提供生成类的包装,而不是(比如说)一系列个体实例变量,通常您只需要打包一个包含状态的映射,如果您需要,这可以包括用于更新状态的原子等对象。

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

您可以根据超级类构造函数定义自己的构造函数并将它们映射到,如下所示在这个有用的指南中。我认为"initialize-after"是一种很好的方法,它可以限制必须放入gen-class中的特定类垃圾。由于您仍然可以通过互操作性操作对象,因此这是一种可行且常用的选择。

by
非常感谢两位抽出时间回答。我在我的小型测试项目中使用seesaw,但某些组件缺失(JDesktopPane,JInternalFrame),因此我不得不研究gen-class并有些困惑(也阅读了kotka.de指南,当您在Google中搜索gen-class时,它是前三个链接之一:)
Tom现在更清晰了,将研究reify/deftype
0
by

可以使用:constructors创建自己的构造函数,但恐怕更好的选择是使用Seesaw,它是Swing的绝佳Clojure包装器。

https://github.com/daveray/seesaw

...