【Clojure】record が「Unable to resolve classname」になる

症状

recordを作って

(ns example-project.shape)

(defrecord Rect [x y width height])

別の名前空間から使おうとすると…

(ns example-project.other
  (:require [example-project.shape :as s]))

(def r1 (s/->Rect 0 0 10 20) ;=> #'example.other/r1
(def r2 (new s/Rect 0 0 10 20) ;=> Unable to resolve classname:
(def r3 (s/Rect. 0 0 10 20) ;=> Unable to resolve classname:

(= (class r1) s/Rect) ;=> No such var: s/Rect

「Unable to resolve」「no such var」エラーになります。

原因

defrecord は java の class を作成する。「.」や「new」は、ただの関数呼び出しではなく、コンストラクタの呼び出し。

そのままでは、現在の名前空間以外で定義された class を参照できない。

対策

importするか、完全なパッケージ名を指定する。ただし、名前空間にハイフンが含まれる場合は、アンダースコアへの置換が必要。

(ns example-project.other
  (:require [example-project.shape :as s])
  (:import [example_project.shape Rect]))

(def r2 (new example_project.shape.Rect 0 0 10 20) 
(def r3 (Rect. 0 0 10 20)