我对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}
答案 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
仅创建位置工厂。