我有两个“lein”项目,两个测试文件中的代码完全相同:
... clojure.set/union ...
第一个项目编译并成功运行。第二个错误出现:
Exception in thread "main" java.lang.ClassNotFoundException: clojure.set, compiling:(foo/bar.clj:14)
...
Caused by: java.lang.ClassNotFoundException: clojure.set
...
如果我在:use
bar.clj
,我只能运行第二个项目
(:use clojure.set)
第一个项目没有这个陈述。为什么不同的行为?
更新:
第一个没有发生例外情况的项目在project.clj
中有以下声明:
:eval-in-leiningen true
答案 0 :(得分:4)
如果希望本地符号引用该命名空间中的名称,则只需声明命名空间的使用。否则,您可以拼出要使用的每个var的全名。请参阅http://clojure.org/namespaces
的第一页普通函数通常存储在var
中,您可以通过完全拼写出名称(clojure.core/+ 1 2)
或通过将封闭名称空间中的符号引用到refer
来访问它。举个例子,我们可以从一个名为bar的完全空白的命名空间开始。它甚至不会从其中的核心Clojure函数开始:
foo> (in-ns 'bar)
#<Namespace bar>
bar> (+ 1 2)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: + in this context, compiling:(NO_SOURCE_PATH:1)
如果我们拼出包含它的+
的全名,我们可以使用var
功能。
bar> (clojure.core/+ 1 2)
3
然后你可以通过调用+
refer
引用它在clojure.core中的变量。
bar> (clojure.core/refer 'clojure.core)
nil
bar> (+ 1 2)
3
<小时/> 至于你的错误,这种情况往往发生在:
(use 'clojure.set)
或(require 'clojure.set)
(ns foo.bar (:use clojure.clj))
表单中声明,而不是在另一个项目中声明答案 1 :(得分:3)
Clojure中的依赖性与大多数其他动态语言非常相似:在明确需要命名空间之前,没有符号可用,因为命名空间不会被加载到运行时;但是,一旦加载了命名空间,其符号就可以从所有命名空间中获得,这解释了您见证的行为。不一致是由于文件加载到运行时的顺序的细节造成的。
命名空间依赖性问题的其他方面仅涉及您取消引用外部命名空间符号的便利程度:
您可以声明名称空间前缀而不是全名:
(require [clojure.string :as s])
这会为您提供(s/join "," coll)
您可以将外部命名空间中的某些符号引用到主命名空间中。这会将本地符号绑定到外部名称空间中的同名对应项:
(require [clojure.string :refer [join]])
为您提供(join "," coll)
您可以声明前缀并引用特定符号:
(require [clojure.string :as s :refer [join]])
为您提供(join "," coll)
以及(s/join "," coll)
您可以将整个命名空间引用到您的家庭命名空间中:
(require [clojure.string :refer :all])
注意:演示的语法仅适用于(ns ...)
表单。当 require 用作独立表单时,必须明确引用所有符号。
正如您所看到的,您所需要的一切(从Clojure 1.4开始)是 require 而使用现在只是一个小方便,适用于您不喜欢的情况。我需要声明一个前缀。
(use clojure.string)
与(require [clojure.string :refer :all])
(use [clojure.string :only [join]])
与(require [clojure.string :refer [join]])
相同。