或者(use '你的命名空间 :reload)
:reload
和:reload-all
)应具有相同的效果。下面是 :reload-all
的完整命令:
(use 'your.namespace :reload-all)
这也会重新加载所有依赖项。 - Jason还有一种替代方案,可以使用tools.namespace,它非常高效:
user=> (use '[clojure.tools.namespace.repl :only (refresh)])
user=> (refresh)
:reloading (namespace.app)
:ok
(refresh)
命令也会导致 REPL 忘记你已经要求了 clojure.tools.namespace.repl
。接下来的 (refresh)
调用将抛出一个 RuntimeException,"Unable to resolve symbol: refresh in this context."。最好的做法可能是要么使用 (require 'your.namespace :reload-all)
命令重新加载命名空间,要么,如果你知道你将要为给定项目频繁地刷新 REPL,就可以创建一个 :dev
配置文件并将 [clojure.tools.namespace.repl :refer (refresh refresh-all)]
添加到 dev/user.clj
中。 - Dave Yarwood(require … :reload)
和:reload-all
重新加载Clojure代码是非常有问题的:clojure.tools.namespace库显著改善了情况。它提供了一个易于使用的刷新功能,可以基于名称空间的依赖图进行智能重新加载。
myapp.web=> (require '[clojure.tools.namespace.repl :refer [refresh]])
nil
myapp.web=> (refresh)
:reloading (myapp.web)
:ok
myapp.web=> (refresh)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: refresh in this context, compiling:(/private/var/folders/ks/d6qbfg2s6l1bcg6ws_6bq4600000gn/T/form-init819543191440017519.clj:1:1)
doc
和source
)不再在其中引用。~/.lein/src/user.clj
中,但您可以将其放在任何地方。该文件应在顶部ns声明中要求刷新函数,如下所示:(ns user
(:require [clojure.tools.namespace.repl :refer [refresh]]))
~/.lein/profiles.clj
中设置一个Leiningen用户配置文件,这样你放置文件的位置就会被添加到类路径中。配置文件应该看起来像这样:{:user {:dependencies [[org.clojure/tools.namespace "0.2.7"]]
:repl-options { :init-ns user }
:source-paths ["/Users/me/.lein/src"]}}
:source-paths
我得到了 #<FileNotFoundException java.io.FileNotFoundException: Could not locate user__init.class or user.clj on classpath: >
的错误,但是使用 :resource-paths
一切正常。 - fl00rlein repl
、Clojure 1.7.0 和 nREPL 0.3.5 的答案。如果您是初学者:命名空间('my.namespace
)在 src/
.../core.clj
中通过 (ns ...)
定义。 - Aaron Digullaproj.stuff.core
)反映了磁盘上的文件结构(如src/proj/stuff/core.clj
),因此REPL可以定位到正确的文件,您不需要使用load-file
。 - Alan Thompson基于papachan的回答,一句话简述如下:
(clojure.tools.namespace.repl/refresh)
我在Lighttable(和令人惊叹的instarepl)中使用这个功能,但它也应该适用于其他开发工具。在重新加载后,我遇到了旧函数和多方法定义仍然存在的同样问题,因此现在在开发过程中,不是通过以下方式声明命名空间:
(ns my.namespace)
我像这样声明我的命名空间:
(clojure.core/let [s 'my.namespace]
(clojure.core/remove-ns s)
(clojure.core/in-ns s)
(clojure.core/require '[clojure.core])
(clojure.core/refer 'clojure.core))
看起来有点丑陋,但每当我重新评估整个命名空间(在Lighttable中按Cmd-Shift-Enter以获取每个表达式的新instarepl结果),它会清除所有旧定义并给我一个干净的环境。 在我开始这样做之前,我每隔几天就被旧定义绊倒了,这挽救了我的理智。 :)
再试一次load-file?
如果您正在使用集成开发环境(IDE),通常有一个键盘快捷键可以将代码块发送到REPL,从而有效地重新定义相关函数。
一旦(use 'foo.bar)
对你起作用,这意味着你的CLASSPATH上有foo/bar.clj或foo/bar_init.class。bar_init.class将是bar.clj的AOT编译版本。如果你执行(use 'foo.bar)
,我不确定Clojure是更喜欢class还是clj文件。如果它更喜欢class文件并且你有两个文件,那么很明显编辑clj文件然后重新加载命名空间没有任何效果。
顺便说一下:如果你的CLASSPATH设置正确,你不需要在use
之前load-file
。
顺便说一下2:如果你因为某种原因需要使用load-file
,那么如果你编辑了文件,可以简单地再次执行它。
(use 'foo.bar :reload-all)
始终有效。如果您的类路径设置正确,则(load-file)
永远不应该是必需的。你所说的“必需效果”是什么? - Dave Raybar.clj
中详细说明“必要效果”。 - Sridhar Ratnakumar(defn f [] 1)
,并将其定义更改为(defn f [] 2)
,那么在我发出(use 'foo.bar :reload-all)
并调用f
函数后,它应该返回 2 而不是 1。不幸的是,对我来说它并不是这样工作的,每次我更改函数体时都必须重新启动 REPL。 - pkaleta:reload
或:reload-all
都应该可以工作。 - Jason