0

Clojure 菜鸟。我无法获得:gen-class工作的基本示例。

$ lein new app pizza-parlor
; project.clj
(defproject pizza-parlor "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.10.1"]]
  :main ^:skip-aot pizza-parlor.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all
                       :jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})

; src/pizza_parlor/Deliverator.clj
(ns pizza-parlor.Deliverator
  (:gen-class))

(defn -deliver [pizza]
  (println "pipin' hot"))

$ lein repl
pizza-parlor.core=> (require 'pizza-parlor.Deliverator)
nil

pizza-parlor.core=> (def d (pizza-parlor.Deliverator.))
Syntax error (ClassNotFoundException) compiling new at (/tmp/form-init10318668819087633543.clj:1:1).
pizza-man.Deliverator

pizza-man.core=> (import pizza-parlor.Deliverator)
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:435).
pizza-parlor.Deliverator

我已经尝试了:aotin 的选项project.clj并运行lein compile以在 中生成类target/default,但我得到了同样的错误。

什么是定义 Java 类的正确方法gen-class,然后在 repl 中与我的项目代码的其余部分一起使用它,或者我可以运行的测试是lein test什么?

4

2 回答 2

1

您必须注意其中带有破折号的名称/文件夹-

“some-clojure-namespace”的 clojure 命名空间将对应于 java 世界(和文件夹结构)中的“some_clojure_namespace”

所以在你的特殊情况下:

; src/pizza-parlor/Deliverator.clj
(ns pizza-parlor.Deliverator

应该在“pizza_parlor”文件夹中,所以:

; src/pizza_parlor/Deliverator.clj
(ns pizza-parlor.Deliverator

接着

(ns pizza-parlor.Deliverator)

将对应于(java)导入:

(import pizza_parlor.Deliverator)

(注意这里的下划线)

但正如@Alan Thompson 所说,您不需要创建类并将它们导入 clojure。您可以要求命名空间并像他描述的那样调用它。如果您必须与 java lib 左右互操作,您希望生成 Java 类并主要导入它们。

您也可以直接使用 gen-class 来生成您需要的任何 Java 类,请参见此处的许多示例

于 2021-03-11T10:10:57.393 回答
1

您误解了如何在 REPL 中执行功能。

您不需要在 Clojure 中“创建一个类”。只需启动一个 repl 并调用一个函数。有几种选择:

(ns demo.core
  ; (:gen-class) ; uncomment to make runnable JAR file
  )

(defn -main []
  (println "main - enter")
  )

正如评论所说,如果你想创建一个可执行的 JAR 文件,你只需要表单(:gen-class)中的表达式。ns

方法一:切换到想要的命名空间,运行函数:

~/expr/demo > lein repl
demo.core=> (in-ns 'demo.core)   ; single-quote is required
demo.core=> (-main)
main - enter

方法 2:只需使用完全限定符号调用函数:

~/expr/demo > lein repl
demo.core=> (demo.core/-main)   ; no quote!
main - enter

这仅适用于由表达式标识的“主要”ns

:main demo.core

project.clj.

方法 3:需要命名空间,然后使用完全限定符号调用函数:

> lein repl
demo.core=> (require 'demo.core)   ; single-quote is required
demo.core=> (demo.core/-main)
main - enter

这适用于任何命名空间,即使demo.coreREPL 将您置于user命名空间中。

方法#4:构建一个可执行的 uberjar

您必须确保它(:gen-class)存在于(ns ...)表格中并且:main demo.core您的project.clj. 然后

~/expr/demo > lein uberjar                                                                         
Created /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT.jar
Created /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT-standalone.jar

~/expr/demo > java -jar /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT-standalone.jar 
main - enter

如果您看到这样的错误消息:

~/expr/demo > java -jar /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT-standalone.jar 
Error: Could not find or load main class demo.core
Caused by: java.lang.ClassNotFoundException: demo.core

然后你忘了(:gen-class)ns表格中包含 。


在此处查看有关 gen-class 的更多详细信息


更新

如果你真的想从 Clojure 代码中创建一个 Java 类,你需要函数 gen-class,而不是ns表达式。看:


更新#2

您真的需要从 Clojure 代码生成 Java 类吗?*.java在源代码文件中编写 Java 类可能更容易。Leiningen 完全能够将混合的 Clojure 和 Java 源代码编译成单个可执行文件。这可能是最简单的方法。

于 2021-03-11T06:06:48.413 回答