何时需要声明命名空间的用法,何时不需要?



我有两个"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
...

如果我在bar.clj中添加显式:use,我只能使第二个项目运行

(:use clojure.set)

第一个项目没有这个语句。为什么会有不同的行为?

:

第一个项目没有发生异常,在project.clj中有以下声明:

:eval-in-leiningen true

只有当您希望局部符号引用该名称空间中的名称时,才需要声明使用该名称空间。否则,您可以拼出要使用的每个变量的全名。参见http://clojure.org/namespaces

首页

普通函数通常存储在var s中,您可以通过拼写完整的名称(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

,则可以使符号+引用与clojure中相同的变量。调用refer

bar> (clojure.core/refer 'clojure.core)
nil
bar> (+ 1 2)
3


至于您的错误,这样的情况往往发生在:

  • 您从REPL运行(use 'clojure.set)(require 'clojure.set),而在该命名空间
  • 从clojure调用函数的代码。set实际上没有被调用,导致您看不到错误。
  • 它在(ns foo.bar (:use clojure.clj))表格中声明在一个项目的文件顶部,而不是在另一个项目

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现在只是在不需要声明前缀的情况下提供了一个小小的便利。

(use clojure.string)(require [clojure.string :refer :all])相同

(use [clojure.string :only [join]])(require [clojure.string :refer [join]])相同

最新更新