【问题标题】:Why ns aliasing inside NON-global scope (let, def) is not working?为什么非全局范围内的 ns 别名 (let, def) 不起作用?
【发布时间】:2018-03-04 14:38:54
【问题描述】:

尝试在 let 中为 ns 设置别名以便能够在本地使用它,但在尝试使用别名时出现错误 CompilerException java.lang.RuntimeException: No such namespace: sss

(ns core 
  (:require [clojure.set]
            [clojure.string])
)

(let [] 
     (alias 'sss 'clojure.string)
     (println (ns-aliases *ns*) "hi1")
     (println (sss/capitalize "hONdURas"))
     ;(println (clojure.string/capitalize "hONdURas")) ;;this works
     (ns-unalias *ns*  'sss)
     (+ 1 2)
)

(println (ns-aliases *ns*))

https://repl.it/repls/NoxiousRubberyComputationallinguistics

【问题讨论】:

  • 不特定于let(def testd (do (alias 'sss 'clojure.string) (sss/trim "")))((fn [] (alias 'sss 'clojure.string) (sss/trim ""))) 是一样的。看起来alias 必须是顶级的。
  • 很遗憾 :( 我希望在每次选择时使用类似于 SQL-way 的别名,我可以为非常不同的表使用相同的别名,因为它们对于每个查询都是本地的
  • 同样奇怪的是,只是把(alias 'sss 'clojure.string) 放入不会导致任何错误
  • 有趣的是,别名 注册:(let [] (alias 'b 'clojure.string) (println "NS:" (ns-aliases *ns*))) 输出 NS: {b #object[clojure.lang.Namespace 0x66bd2083 clojure.string]}。但是,如果您尝试 使用 别名,则整个事情都会在 println 甚至可以运行之前因编译器异常而失败。这几乎看起来像一个错误。
  • @Carcigenicate (let [] ...) 并不总是与 (do ...) 相同。在文件的顶层,(do ...) 中的每个子表达式都是单独编译和执行的。相反,(let [] ...) 遵循通常的求值规则,在求值之前一次编译整个表达式(包括所有子表达式)。如果您要更改环境,例如通过添加命名空间别名,这可能会有所不同。

标签: clojure namespaces


【解决方案1】:

(alias ...) 不必是顶级的。 clojure 的工作方式是有一个称为 reader 的东西,它接收文本数据并将其转换为作为编译器输入的数据结构。见

https://clojure.org/reference/reader

代码中引用的任何命名空间都必须在使用前为读者定义。 (函数也一样)。

所以,在

(let [] 
    (alias 'sss 'clojure.string)
    (println (sss/capitalize "aaa")))

阅读器试图转动时没有分配别名

(sss/capitalize)

数据。

【讨论】:

  • 你的意思是alias 也像require 一样定义了[temporal] 命名空间吗? (暂时的,因为ns-unalias 可以做到)
  • 嗯,[时间] 是什么意思? (alias ...) 与 :as in require 完全一样,参见github.com/clojure/clojure/blob/clojure-1.9.0/src/clj/clojure/…
  • 似乎我不是在别名中而是在阅读 sss/ 时理解这个问题。好吧,我希望别名有类似 (the-ns 'sss) 的东西:/
  • 另外,请尝试ns-interns,它会返回所有 ns 符号的映射,而不是一一解析。
  • 在局部范围的上下文中考虑 var 命名空间是非惯用的 clojure,而且它也没有真正的意义。别名指向 var 命名空间,这是依赖解析的机制。根据定义,var 命名空间相当于 clojure 的模块范围使用本地别名类似于在 let 中执行 (def ...) 或 (defn)。而且它们不是并发安全的。
猜你喜欢
  • 2018-08-06
  • 2017-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 2011-05-11
  • 2020-06-22
相关资源
最近更新 更多