如果我有一个名称空间是别名的符号,例如 q/w,我怎样才能找到它的实际名称空间,比如 actual.namespace/w ?
我知道这resolve
会给我完全限定的 var,但我不知道如何获取 var 的命名空间。
我能做的最好的是:
(defn fqns [s] (str (get (ns-aliases *ns*) (symbol (namespace s)))))
肯定有更简单的方法吗?
如果我有一个名称空间是别名的符号,例如 q/w,我怎样才能找到它的实际名称空间,比如 actual.namespace/w ?
我知道这resolve
会给我完全限定的 var,但我不知道如何获取 var 的命名空间。
我能做的最好的是:
(defn fqns [s] (str (get (ns-aliases *ns*) (symbol (namespace s)))))
肯定有更简单的方法吗?
您可以获得符号的命名空间对象,如下所示(如果您希望 ns 的名称作为字符串,则只需在最后调用 str ):
(defn fqns [s] (->> (resolve s) meta :ns))
符号本身与任何命名空间对象没有直接联系;它的命名空间部分只是一个内部字符串。只有当它被resolve
d 时,该字符串才被视为要在其中查找 Var 的实际名称空间的名称。(特别是,您可以在foo/bar
不创建名称空间foo
或注册foo
为名称空间别名的情况下创建符号。)因此,您需要自己完成resolve
或完成它的部分工作。
在第一种情况下,您可以说(在最近的 Clojure 版本中;或者您可以跳过表示属性访问的连字符 -- 而不是-ns
, 使用ns
-- 以向后兼容)
(.. (resolve s) -ns -name)
这会解析一个 Var 对象,然后从其字段中提取对其命名空间的引用ns
,最后从其字段中提取命名空间的符号名称name
。(注意namespace
andname
函数不起作用,因为 Vars 和命名空间没有实现clojure.lang.Named
。)
问题文本中的函数也很好,尽管从命名空间中提取符号名称会更好(.-name (get ...))
——而不是toString
通过使用str
.
您可能还想添加clojure.lang.Var
和clojure.lang.Namespace
键入提示以避免在您的调用中产生反射。(如果您希望它们更快,或者如果您需要*warn-on-reflection*
调整其他性能以提高性能并希望避免此处出现无用的警告。)
如果您希望处理命名空间不存在的可能性(并nil
在这种情况下返回,与通常的 Clojure 习惯用法保持一致):
(defn fqns
([s]
(fqns (.-name *ns*) s))
([ns s]
(some-> ns
find-ns
.-name
ns-aliases
(get (symbol (namespace s)))
.-name)))
if-let
或者在 Clojure 1.4 和更早的版本中使用一些s。