【问题标题】:Why does "use" in Clojure call "in-ns" to return to the original namespace?为什么 Clojure 中的“use”调用“in-ns”返回原来的命名空间?
【发布时间】:2014-07-27 22:54:33
【问题描述】:

在 Clojure 中,use 加载一个库,此外还引用该库的命名空间。

loaddoes not change the current namespace.

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

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)是不是没必要?

【问题讨论】:

    标签: clojure namespaces


    【解决方案1】:

    它实际上并没有调用in-ns——它只在“详细加载”时打印这一行(也就是说,如果你将:verbose作为use的一个选项传递给use),这样你就知道引用的是哪个命名空间发生在。如果您使用 :as 调用 require 以明确将在哪个命名空间中创建别名,它也会这样做:

    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)

    【讨论】:

      【解决方案2】:

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

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

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

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

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

      用户=>(使用 '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 在正确的命名空间中执行是绝对必要的。否则将从用户命名空间执行。

      【讨论】:

        猜你喜欢
        • 2015-05-26
        • 1970-01-01
        • 2017-01-17
        • 1970-01-01
        • 1970-01-01
        • 2011-09-19
        • 1970-01-01
        • 1970-01-01
        • 2011-08-31
        相关资源
        最近更新 更多