为什么"使用"在Clojure电话" in-ns"返回原始命名空间?

时间:2014-07-27 22:54:34

标签: clojure namespaces

在Clojure中use加载一个lib,另外还引用了lib的命名空间。

load does not change the current namespace

那么当用in-ns加载lib时隐式调用use命令的目的是什么?

user=> (use 'project.core :verbose)
(clojure.core/load "/project/core")
(clojure.core/in-ns 'user)
(clojure.core/refer 'project.core)

换句话说,上一个例子中(clojure.core/in-ns 'user)不是不必要的吗?

2 个答案:

答案 0 :(得分:4)

它实际上并没有调用in-ns - 它只在“详细加载”时打印此行(即,如果您将:verbose作为选项传递给use),那么你知道引用发生在哪个命名空间。如果你用require调用:as来清楚在哪个命名空间中创建别名,那么它也会这样做:

user=> (require '[clojure.set :as set] :verbose)
(clojure.core/load "/clojure/set")
(clojure.core/in-ns 'user)
(clojure.core/alias 'set 'clojure.set)

当初始加载导致递归加载更多名称空间时,这很有用。例如,这里是(require '[clojure.core.rrb-vector :as fv] :verbose)的输出(可以说refer行也可以使用解释性的in-ns行处理):

(clojure.core/load "/clojure/core/rrb_vector")
(clojure.core/load "/clojure/core/rrb_vector/protocols")
(clojure.core/refer 'clojure.core.rrb-vector.protocols :refer '[slicev splicev])
(clojure.core/load "/clojure/core/rrb_vector/nodes")
(clojure.core/refer 'clojure.core.rrb-vector.nodes :refer '[ams object-am object-nm primitive-nm empty-pv-node empty-gvec-node])
(clojure.core/load "/clojure/core/rrb_vector/rrbt")
(clojure.core/refer 'clojure.core.rrb-vector.protocols :refer '[PSliceableVector slicev PSpliceableVector splicev])
(clojure.core/refer 'clojure.core.rrb-vector.nodes :refer '[ranges overflow? last-range regular-ranges first-child last-child remove-leftmost-child replace-leftmost-child replace-rightmost-child fold-tail new-path index-of-nil object-am object-nm primitive-nm])
(clojure.core/load "/clojure/core/rrb_vector/transients")
(clojure.core/refer 'clojure.core.rrb-vector.nodes :refer '[ranges last-range])
(clojure.core/refer 'clojure.core.rrb-vector.transients :refer '[transient-helper])
(clojure.core/load "/clojure/core/rrb_vector/fork_join")
(clojure.core/load "/clojure/core/reducers")
(clojure.core/in-ns 'clojure.core.reducers)
(clojure.core/alias 'walk 'clojure.walk)
(clojure.core/in-ns 'clojure.core.rrb-vector.fork-join)
(clojure.core/alias 'r 'clojure.core.reducers)
(clojure.core/in-ns 'clojure.core.rrb-vector.rrbt)
(clojure.core/alias 'fj 'clojure.core.rrb-vector.fork-join)
(clojure.core/refer 'clojure.core.protocols :refer '[IKVReduce])
(clojure.core/in-ns 'clojure.core.rrb-vector.rrbt)
(clojure.core/alias 'r 'clojure.core.reducers)
(clojure.core/refer 'clojure.core.reducers :refer '[CollFold coll-fold])
(clojure.core/refer 'clojure.core.rrb-vector.rrbt :refer '[as-rrbt])
(clojure.core/load "/clojure/core/rrb_vector/interop")
(clojure.core/refer 'clojure.core.rrb-vector.protocols :refer '[PSliceableVector slicev PSpliceableVector splicev])
(clojure.core/refer 'clojure.core.rrb-vector.rrbt :refer '[as-rrbt])
(clojure.core/in-ns 'user)
(clojure.core/alias 'fv 'clojure.core.rrb-vector)

以下是clojure.core/load-lib来源的相关片段(打印输出的来源):

;; as of Clojure 1.6.0
(when (and need-ns *loading-verbosely*)
  (printf "(clojure.core/in-ns '%s)\n" (ns-name *ns*)))
(when as
  (when *loading-verbosely*
    (printf "(clojure.core/alias '%s '%s)\n" as lib))
  (alias as lib))

need-ns是一个本地,其值为(or as use) - 也就是说,如果指定了:as别名或者加载是由use引起的,那就是真实的。

如果您想检查整个功能,请在REPL中说(source clojure.core/load-lib)

答案 1 :(得分:1)

注意:忽略初始时间戳。 MichałMarczyk在正确的答案上领先于我。我很快就删除了我最初的错误答案,当我注意到MichałMarczyk的答案时,我刚刚写了这个纠正。

详细输出是您需要在REPL执行以获得相同效果的子命令集,而不是正在执行的实际命令。

在执行的线程中,命名空间 正在被更改,因此在in-ns之前不需要load之后的实际refer/alias命令来确保正确的目标命名空间。

然而,在REPL中,load不会更改REPL的名称空间,因此可能需要在refer/alias之前确保正确的名称空间。这在递归引用或别名时发生。

对于复杂的库,这一点更为明显:

user=> (use 'clojure.core.async :verbose)
(clojure.core/load "/clojure/core/async")
(clojure.core/load "/clojure/core/async/impl/protocols")
(clojure.core/in-ns 'clojure.core.async)
(clojure.core/alias 'impl 'clojure.core.async.impl.protocols)
...

如果我们在REPL中跟随,in-ns对于alias在正确的命名空间中执行是绝对必要的。否则,它将从用户名称空间执行。