Java 如何在Clojure中正确导入用户定义的类

Java 如何在Clojure中正确导入用户定义的类,java,clojure,leiningen,nrepl,Java,Clojure,Leiningen,Nrepl,我正在使用Leiningen和Clojure,就我个人而言,我无法理解为什么Clojure会让正确导入名称空间变得如此困难。这是以下错误 这是我的core.clj文件中的内容: ; namespace macro (ns animals.core (:require animals.animal) (:use animals.animal) (:import (animals.animal Dog)) (:import (animals.animal Human)) (:im

我正在使用Leiningen和Clojure,就我个人而言,我无法理解为什么Clojure会让正确导入名称空间变得如此困难。这是以下错误

这是我的
core.clj
文件中的内容:

; namespace macro
(ns animals.core
  (:require animals.animal)
  (:use animals.animal)
  (:import (animals.animal Dog))
  (:import (animals.animal Human))
  (:import (animals.animal Arthropod))
  (:import (animals.animal Insect)))

; make-animals will create a vector of animal objects
(defn make-animals []
  (conj []
        (Dog. "Terrier" "Canis lupis familiaris")
        (Human. "Human" "Homo sapiens")
        (Arthropod. "Brown Recluse" "Loxosceles reclusa")
        (Insect. "Fire Ant" "Solenopsis conjurata")))

; print-animals will print all the animal objects
(defn print-animals [animals]
  (doseq [animal animals]
    (println animal)))

; move-animals will call the move action on each animal
(defn move-animals [animals]
  (doseq [animal animals]
    (animals.animal/move animal)))

; entry to main program
(defn -main [& args]
  (let [animals make-animals]
    (do
      (println "Welcome to Animals!")
      (println "-------------------")
      (print-animals animals))))
然后,在REPL中输入以下内容(在
lein
项目的src/目录中):

好的。。。什么?为什么?

以下是我的文件
animal.clj
,也在
animals
目录中,以供参考:

(ns animals.animal)

(defprotocol Animal
  "A simple protocol for animal behaviors."
  (move [this] "Method to move."))

(defrecord Dog [name species]
  Animal
  (move [this] (str "The " (:name this) " walks on all fours.")))

(defrecord Human [name species]
  Animal
  (move [this] (str "The " (:name this) " walks on two legs.")))

(defrecord Arthropod [name species]
  Animal
  (move [this] (str "The " (:name this) " walks on eight legs.")))

(defrecord Insect [name species]
  Animal
  (move [this] (str "The " (:name this) " walks on six legs.")))

将您的代码粘贴到新的Leiningen项目中后,由于
-main
(让[动物制作动物]…)
应该是
(让[动物(制作动物)]…)
。通过此更改,一切正常:

user=> (require 'animals.core)
nil
user=> (animals.core/-main)
Welcome to Animals!
-------------------
#animals.animal.Dog{:name Terrier, :species Canis lupis familiaris}
#animals.animal.Human{:name Human, :species Homo sapiens}
#animals.animal.Arthropod{:name Brown Recluse, :species Loxosceles reclusa}
#animals.animal.Insect{:name Fire Ant, :species Solenopsis conjurata}
nil
顺便说一句,从哪里调用
lein repl
并不重要,只要它在项目目录中的某个地方就行

我大胆猜测,当您第一次尝试
要求
它时,您的名称空间出现了问题,而现在由于REPL中的某个名称空间加载状态,它将无法加载。您可能想尝试
(要求:重新加载'anists.core)
,如果不起作用,请重新启动REPL。(如果再次遇到,您还可以将整个REPL交互粘贴到
ClassNotFoundException
的某个位置。)

另外,关于您的
ns
表单:

  • 您不应该同时使用
    :require
    :相同的命名空间<代码>:已经使用了<代码>:需要它

  • 更常见的是使用单个
    :import
    子句(实际上,每个子句类型使用一个子句);比如说,

    (:import (animals.animal Dog Human Arthropod Insect))
    
    这在Clojure中纯粹是一个风格问题,但在ClojureScript中,它实际上是语言所需要的


  • 另一方面,如果已经需要名称空间,甚至不需要导入类。每个记录都定义了两个附加函数,即带有前缀的记录名称<代码>->Record
    的行为类似于构造函数,但它是一个函数<代码>映射->记录
    获取属性映射。例如,这可以允许您使用
    (anists.core/->Dog“Terrier”“Canis lupis familis”)
    ,并可能使您的代码在Clojure实现中更易于移植。
    (:import (animals.animal Dog Human Arthropod Insect))