Clojure在使用和要求之间的差异

时间:2010-08-04 17:25:56

标签: clojure namespaces

我最近开始学习Clojure,而且我在使用命名空间时遇到了一些困难。正如Clojure的创造者所说,新人往往很难将这个概念弄清楚。我不清楚(use ...)(require ...)之间的区别。例如,如果我说(use 'clojure.contrib.str-utils2)在REPL中玩,我会收到有关clojure.core命名空间中的函数被clojure.contrib.str-utils2中的函数替换的警告,但是当我使用{{{ 1}}。我不确定我是否总是想要替换clojure.core中的内容,那么有人可以指出一些最佳实践来导入外部内容并在Clojure中管理名称空间吗?

哦,还有,我应该何时使用(require 'clojure.contrib.str-utils2):use?只在:require内?

提前致谢。

1 个答案:

答案 0 :(得分:42)

答案在于文档字符串:

user> (doc use)
-------------------------
clojure.core/use
([& args])
  Like 'require, but also refers to each lib's namespace using
  clojure.core/refer. Use :use in the ns macro in preference to calling
  this directly.

  'use accepts additional options in libspecs: :exclude, :only, :rename.
  The arguments and semantics for :exclude, :only, and :rename are the same
  as those documented for clojure.core/refer.
nil

长期要求:

user> (doc require)
-------------------------
clojure.core/require
([& args])
  Loads libs, skipping any that are already loaded. Each argument is
  either a libspec that identifies a lib, a prefix list that identifies
  multiple libs whose names share a common prefix, or a flag that modifies
  how all the identified libs are loaded. Use :require in the ns macro
  in preference to calling this directly.

  Libs

  A 'lib' is a named set of resources in classpath whose contents define a
  library of Clojure code. Lib names are symbols and each lib is associated
  with a Clojure namespace and a Java package that share its name. A lib's
  name also locates its root directory within classpath using Java's
  package name to classpath-relative path mapping. All resources in a lib
  should be contained in the directory structure under its root directory.
  All definitions a lib makes should be in its associated namespace.

  'require loads a lib by loading its root resource. The root resource path
  is derived from the lib name in the following manner:
  Consider a lib named by the symbol 'x.y.z; it has the root directory
  <classpath>/x/y/, and its root resource is <classpath>/x/y/z.clj. The root
  resource should contain code to create the lib's namespace (usually by using
  the ns macro) and load any additional lib resources.

  Libspecs

  A libspec is a lib name or a vector containing a lib name followed by
  options expressed as sequential keywords and arguments.

  Recognized options: :as
  :as takes a symbol as its argument and makes that symbol an alias to the
    lib's namespace in the current namespace.

  Prefix Lists

  It's common for Clojure code to depend on several libs whose names have
  the same prefix. When specifying libs, prefix lists can be used to reduce
  repetition. A prefix list contains the shared prefix followed by libspecs
  with the shared prefix removed from the lib names. After removing the
  prefix, the names that remain must not contain any periods.

  Flags

  A flag is a keyword.
  Recognized flags: :reload, :reload-all, :verbose
  :reload forces loading of all the identified libs even if they are
    already loaded
  :reload-all implies :reload and also forces loading of all libs that the
    identified libs directly or indirectly load via require or use
  :verbose triggers printing information about each load, alias, and refer

  Example:

  The following would load the libraries clojure.zip and clojure.set
  abbreviated as 's'.

  (require '(clojure zip [set :as s]))
nil

他们都做同样的事情,但是use进行了额外的步骤,并为当前命名空间中require'd命名空间中的内容创建了映射。这样,您只需将some.namespace/name称为name,而不是(ns whatever (:use [some.namespace :only [vars you want]])) 。虽然这有时很方便,但最好使用require或选择所需的单个变量而不是拉入整个命名空间。否则,您可能会遇到阴影问题(其中一个var优先于另一个同名)。

如果您不想使用require,但是您知道要从命名空间中删除哪些变量,则可以执行以下操作:

(ns whatever
  (:require [some.namespace :as sn]))

如果你不知道你需要哪些变量,或者你需要很多变量,那么最好使用require。即使您需要,也不必总是输入完全限定的名称。你可以这样做:

(sn/somefunction arg1 arg2)

然后您可以使用some.namespace中的变量,如下所示:use

并回答你的上一个问题:尝试只使用:require和:在(ns ...)内使用。这种方式更干净。除非你有充分的理由,否则不要在{ns}之外require和{{1}}。