4

如果我有一个名称空间是别名的符号,例如 q/w,我怎样才能找到它的实际名称空间,比如 actual.namespace/w ?

我知道这resolve会给我完全限定的 var,但我不知道如何获取 var 的命名空间。

我能做的最好的是:

 (defn fqns [s] (str (get (ns-aliases *ns*) (symbol (namespace s)))))

肯定有更简单的方法吗?

4

2 回答 2

8

您可以获得符号的命名空间对象,如下所示(如果您希望 ns 的名称作为字符串,则只需在最后调用 str ):

(defn fqns [s] (->> (resolve s) meta :ns))
于 2013-04-18T06:53:53.370 回答
2

符号本身与任何命名空间对象没有直接联系;它的命名空间部分只是一个内部字符串。只有当它被resolved 时,该字符串才被视为要在其中查找 Var 的实际名称空间的名称。(特别是,您可以在foo/bar不创建名称空间foo或注册foo为名称空间别名的情况下创建符号。)因此,您需要自己完成resolve或完成它的部分工作。

在第一种情况下,您可以说(在最近的 Clojure 版本中;或者您可以跳过表示属性访问的连字符 -- 而不是-ns, 使用ns-- 以向后兼容)

(.. (resolve s) -ns -name)

这会解析一个 Var 对象,然后从其字段中提取对其命名空间的引用ns,最后从其字段中提取命名空间的符号名称name。(注意namespaceandname函数不起作用,因为 Vars 和命名空间没有实现clojure.lang.Named。)

问题文本中的函数也很好,尽管从命名空间中提取符号名称会更好(.-name (get ...))——而不是toString通过使用str.

您可能还想添加clojure.lang.Varclojure.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。

于 2013-04-18T09:25:03.197 回答