2010-09-11 4 views
12

Ich habe ein Projekt mit leiningen namens Techne eingerichtet. Ich habe ein Modul namens scrub mit einem Typ namens Scrub und einer Funktion namens foo erstellt.Wie verwenden Sie einen Typ außerhalb seines eigenen Namensraums in clojure?

Techne/scrub.clj:

(ns techne.scrub) 
    (deftype Scrub [state] 
    Object 
    (toString [this] 
    (str "SCRUB: " state))) 

(defn foo 
    [item] 
    (Scrub. "foo") 
    "bar") 

Techne/scrub_test.clj:

(ns techne.scrub-test                                    
    (:use [techne.scrub] :reload-all)                                
    (:use [clojure.test]))                                   


(deftest test-foo                                     
    (is (= "bar" (foo "foo"))))                                       

(deftest test-scrub                                    
    (is (= (Scrub. :a) (Scrub. :a)))) 

Wenn ich den Test ausführen, bekomme ich die Fehlermeldung:

Exception in thread "main" java.lang.IllegalArgumentException: Unable to resolve classname: Scrub (scrub_test.clj:11) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:5376) 
    at clojure.lang.Compiler.analyze(Compiler.java:5190) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:5357) 

Wenn ich Test-Scrub entfernen alles funktioniert gut. Warum: Verwenden Sie techne.scrub 'importieren' die Funktionsdefinitionen, aber nicht die Typdefinitionen? Wie referenziere ich die Typdefinitionen?

Antwort

15

Da deftype eine Klasse generiert, müssen Sie diese Java-Klasse wahrscheinlich in techne.scrub-test mit (: import [techne.scrub Scrub]) in Ihre ns-Definition importieren.

schrieb ich tatsächlich diese gleiche Sache in Bezug auf hier defrecord:

Eine andere Sache, die Sie wäre tun könnte eine Konstruktorfunktion in Gestrüpp zu definieren:

(defn new-scrub [state] 
    (Scrub. state)) 

und dann müssten Sie Scrub nicht im Test-Scrub importieren.

+1

Ich benutze immer Konstruktorfunktionen aus diesem Grund und für die Validierung. –

+1

Ja, wir haben herausgefunden, dass es hilfreich ist, den Defrecord zu erweitern, um Konstruktorfunktionen automatisch mit Feldvalidierung, pprint Unterstützung zu einem eval-fähigen Formular usw. hinzuzufügen. –

+4

Beachten Sie, dass diese Antwort vor Clojure 1.4 liegt. Seit 1.4 wird ein positioneller (-> Scrub) und map (map-> Scrub) -Konstruktor automatisch durch Defrecord erzeugt. Dies ist die bevorzugte Methode der Konstruktion und erfordert nur, dass Sie diese Funktionen in Ihren Namespace verweisen - Sie müssen die Klasse nicht importieren. –

0

Ich füge den Import hinzu, bekomme aber das selbe Problem. Ich teste mit dem Expectations-Paket 2.0.9 und versuche, defType Node und Interface INode zu importieren.

In core.clj:

(ns linked-list.core) 

(definterface INode 
    (getCar []) 
    (getCdr []) 
    (setCar [x]) 
    (setCdr [x])) 

(deftype Node [^:volatile-mutable car ^:volatile-mutable cdr] 
    INode 
    (getCar[_] car) 
    (getCdr[_] cdr) 
    (setCar[_ x] (set! car x) _) 
    (setCdr[_ x] (set! cdr x) _)) 

In core_test.clj:

(ns linked-list.core-test 
    (:require [expectations :refer :all] 
      [linked-list.core :refer :all]) 
    (:import [linked-list.core INode] 
      [linked-list.core Node])) 

und die Ausgabe von Lein autoexpect:

*************** Running tests *************** 
Error refreshing environment: java.lang.ClassNotFoundException: linked-list.core.INode, compiling:(linked_list/core_test.clj:1:1) 
Tests completed at 07:29:36.252 

Der Vorschlag, eine Fabrik-Methode zu verwenden, ist jedoch eine praktikable Lösung.

Verwandte Themen