在 repl 中使用必需的命名空间

Using required namespace in the repl

当我在 clojure 脚本源文件中需要一个命名空间时,我可以随后在代码中使用它。

例如:

(ns my.core
  (:require [mylib.core :as lib]))

(lib/my-f)

(def something 99)

但是,当我尝试在 repl 中调用 (lib/my-f) 时 - 通过 (ns my.core) 更改名称空间后 - 我无法访问它。相反,ns 中的所有其他定义都是可访问的:如上面示例中的 something

有没有办法访问 repl 中的要求?还是我每次都必须在 repl 中手动要求它们?这当然会很乏味。

只要在使用 nsin-ns 切换到它之前 require 命名空间,这一切都应该可以正常工作。令我困惑的是 something 是可访问的,这意味着您的代码已加载:这应该意味着它的命名空间形式也被评估,因此您应该可以使用它的别名。你确定你是从一个新的状态开始做的,并且没有,比如说,独立定义 something 吗?仔细检查:

  1. 关闭repl
  2. 开始新的回复
  3. (require 'my.core)
  4. (in-ns 'my.core)
  5. 检查你问题中的内容是否仍然正确。您仍然可以访问 something? 您仍然可以 不能 访问 lib/my-f 吗?我预计这两件事之一会发生变化:您应该无法访问任何一个,或两者都无法访问。

如果您使用 ns 更改 ClojureScript REPL 中的命名空间,这会将命名空间别名设置为与 ns 表单中使用的别名相匹配。

这是一个说明这个概念的例子:

$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (ns foo.core (:require [clojure.string :as string]))

foo.core=> (string/starts-with? "abc" "a")
true
foo.core=> (ns bar.core)

bar.core=> (ns foo.core)

foo.core=> (string/starts-with? "abc" "a")
WARNING: No such namespace: string, could not locate string.cljs, string.cljc, or Closure namespace "" at line 1 <cljs repl>
WARNING: Use of undeclared Var string/starts-with? at line 1 <cljs repl>
ReferenceError: "string" is not defined

如果您改为使用 in-ns REPL 特殊更改为现有名称空间,这将保留别名:

$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (ns foo.core (:require [clojure.string :as string]))

foo.core=> (string/starts-with? "abc" "a")
true
foo.core=> (ns bar.core)

bar.core=> (in-ns 'foo.core)
nil
foo.core=> (string/starts-with? "abc" "a")
true

一个有趣的相关方面:如果您使用 require,它会在幕后采用 ns 形式,并将特殊元烘焙到保留现有别名的形式中:

$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (require '[clojure.string :as string])
nil
cljs.user=> (require '[clojure.string :as str])
nil
cljs.user=> (string/starts-with? "abc" "a")
true
cljs.user=> (str/starts-with? "abc" "a")
true

如果你很好奇,这里是 :merge true 元数据:https://github.com/clojure/clojurescript/blob/r1.7.228/src/main/clojure/cljs/repl.cljc#L679

这里的分析器很荣幸:https://github.com/clojure/clojurescript/blob/r1.7.228/src/main/clojure/cljs/analyzer.cljc#L1953

通过了解它是如何工作的,它应该提供一些洞察力,以了解为什么直接在 REPL 中评估的 ns 表单(没有 merge 元数据)会导致别名被清除。

简而言之,避免直接使用 ns special 更改为 REPL 中的命名空间。而是使用它在 REPL 中创建一个新的命名空间,同时指定任何所需的命名空间。

使用 in-ns 特殊 REPL 切换到现有命名空间。它还可以用于创建新的命名空间。

使用 require 将命名空间加载到 REPL 中,然后使用 in-ns 切换到它们。