在 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 中手动要求它们?这当然会很乏味。
只要在使用 ns
或 in-ns
切换到它之前 require
命名空间,这一切都应该可以正常工作。令我困惑的是 something
是可访问的,这意味着您的代码已加载:这应该意味着它的命名空间形式也被评估,因此您应该可以使用它的别名。你确定你是从一个新的状态开始做的,并且没有,比如说,独立定义 something
吗?仔细检查:
- 关闭repl
- 开始新的回复
(require 'my.core)
(in-ns 'my.core)
- 检查你问题中的内容是否仍然正确。您仍然可以访问
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
切换到它们。
当我在 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 中手动要求它们?这当然会很乏味。
只要在使用 ns
或 in-ns
切换到它之前 require
命名空间,这一切都应该可以正常工作。令我困惑的是 something
是可访问的,这意味着您的代码已加载:这应该意味着它的命名空间形式也被评估,因此您应该可以使用它的别名。你确定你是从一个新的状态开始做的,并且没有,比如说,独立定义 something
吗?仔细检查:
- 关闭repl
- 开始新的回复
(require 'my.core)
(in-ns 'my.core)
- 检查你问题中的内容是否仍然正确。您仍然可以访问
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
切换到它们。