Einige Dinge sind immer noch als Java-Schnittstellen in Clojure implementiert; von diesen werden einige wahrscheinlich für immer so bleiben, um die Zusammenarbeit mit Clojure-Code aus anderen JVM-Sprachen zu erleichtern.
Glücklicherweise kann man bei der Definition eines Typs mit deftype
können Sie den neuen Typ alle Java-Schnittstellen implementieren lassen, die Sie benötigen (was Brian in einem Kommentar oben erwähnt hat), sowie alle Methoden von java.lang.Object
. Ein Beispiel, das Ihrer Beschreibung entspricht, könnte wie folgt aussehen:
(deftype Foo [a b]
clojure.lang.IPersistentCollection
(seq [self] (if (seq a) self nil))
(cons [self o] (Foo. a (conj b o)))
(empty [self] (Foo. [] []))
(equiv
[self o]
(if (instance? Foo o)
(and (= a (.a o))
(= b (.b o)))
false))
clojure.lang.ISeq
(first [self] (first a))
(next [self] (next a))
(more [self] (rest a))
Object
(toString [self] (str "Foo of a: " a ", b: " b)))
Ein Beispiel dafür, was man damit in der REPL machen kann:
user> (.toString (conj (conj (Foo. [] []) 1) 2))
"Foo of a: [], b: [1 2]"
user> (.toString (conj (conj (Foo. [:a :b] [0]) 1) 2))
"Foo of a: [:a :b], b: [0 1 2]"
user> (first (conj (conj (Foo. [:a :b] [0]) 1) 2))
:a
user> (Foo. [1 2 3] [:a :b :c])
(1 2 3)
Beachten Sie, dass die REPL druckt es als eine seq; Ich glaube, das ist wegen der Inline-Implementierung von clojure.lang.ISeq
. Sie können es weglassen und die seq
Methode mit einer zurückgebenden (seq a)
für eine gedruckte Darstellung unter Verwendung der benutzerdefinierten toString
. str
verwendet immer toString
Allerdings.
Wenn Sie ein benutzerdefiniertes Verhalten von pr
Familienfunktionen (einschließlich println
usw.), müssen Sie sich mit der Implementierung eines benutzerdefinierten print-method
für Ihren Typ. print-method
ist eine Multimethode, die in clojure.core
; schauen Sie sich an core_print.clj in den Clojure-Quellen für Beispielimplementierungen.