为什么我不能在使用其命名空间后实例化一个defrecord生成的类?

时间:2013-08-03 17:33:52

标签: clojure

我对Clojure来说相对较新,并且通过七周七种语言中的Clojure章节,我无法弄清楚为什么这本书中的代码不是&#39为我工作。我使用Leiningen和Clojure 1.5.1版。据我仔细检查后可以看出,我输入的代码完全按照书中的内容输入。

以下是代码:

(ns seven-languages.compass)

(defprotocol Compass
    (direction [c])
    (left [c])
    (right [c]))

(def directions [:north :east :south :west])

(defn turn [base amount]
    (rem (+ base amount) (count directions)))

(defrecord SimpleCompass [bearing]
    Compass
    (direction [_] (directions bearing))
    (left [_] (SimpleCompass. (turn bearing 3)))
    (right [_] (SimpleCompass. (turn bearing 1)))

    Object
    (toString [this] (str "[" (direction this) "]")))

我正在跑步" lein repl"来自目录〜/ clojure /七种语言(通过运行" lein new seven-languages"在〜/ clojure中创建)。相对于此目录,我的.clj文件位于src / seven_languages中。到目前为止,我已经能够通过输入(use 'seven-languages.filenamehere)成功导入并在repl中使用它们。

因此,在将上面列出的代码保存为src / seven_languages / compass.clj之后,我从REPL运行它:

user=> (use 'seven-languages.compass)
nil

但是当我尝试定义一个"实例"在SimpleCompass中,输入就像在书中一样,这种情况发生了:

user=> (def c (SimpleCompass. 0))

CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: SimpleCompass, compiling:(NO_SOURCE_PATH:1:8)

我也尝试使用(load-file "src/seven_languages/compass.clj")加载文件,但结果相同。由于实际加载似乎按预期工作,我想知道在编写七周七种语言之后,在Clojure版本中defprotocol或defrecord的工作方式是否有所改变。在Clojure章节的介绍中,作者写道,"我正在使用Clojure 1.2的预发布版本,它应该在本书掌握之前完全准备好。"

有人能说出为什么这段代码不能正常工作吗?如果是版本问题,您如何更新Clojure 1.5.1的代码?

编辑:啊哈!我发现这一点后想出来了:
Clojure - deftype ignored - unable to resolve classname on tests

这是命名空间问题。我猜这是从版本1.2开始编写7LI7W时的一个变化。无论出于何种原因,导入文件中的功能都会自动处理"这样你就可以直接使用它们,不会自动处理类型。您必须包含该类型的完整路径,并确保使用带下划线的实际路径,而不是连字符。我通过用SimpleCompass完整路径代替seven_languages.compass.SimpleCompass来获得我的代码:

user=> (def c (seven_languages.compass.SimpleCompass. 0))
#'user/c
user=> c
#seven_languages.compass.SimpleCompass{:bearing 0}
user=> (left c)
#seven_languages.compass.SimpleCompass{:bearing 3}
user=> (right c)
#seven_languages.compass.SimpleCompass{:bearing 1}

1 个答案:

答案 0 :(得分:3)

除了始终完全限定班级名称外,您可以import之后使用短名称:

(import seven_languages.compass.SimpleCompass)

;; (SimpleCompass. 0) etc. will work now

此外,值得指出的是defrecord为您创建工厂函数,一个位置,另一个制作地图:

(defrecord Foo [x])

(->Foo 1)
;= #user.Foo{:x 1}
(map->Foo {:x 1})
;= #user.Foo{:x 1}

这些只是常规功能,因此会被use来电拉入。

相关地,从Clojure 1.5.1开始,deftype仅创建位置工厂。