符号本身与任何命名空间对象没有直接联系;它的命名空间部分只是一个内部字符串。只有当它是resolved 时,该字符串才被视为要在其中查找 Var 的实际命名空间的名称。 (特别是,您可以创建符号 foo/bar 而无需创建命名空间 foo 或将 foo 注册为命名空间的别名。)因此,您需要通过 resolve 或自己完成部分工作.
在第一种情况下,您可以说(在最近的 Clojure 版本中;或者您可以跳过表示属性访问的连字符 -- 使用 -ns 代替 ns -- 以向后兼容)
(.. (resolve s) -ns -name)
这会解析一个 Var 对象,然后从其 ns 字段中提取对其命名空间的引用,最后从其 name 字段中提取命名空间的符号名称。 (注意namespace 和name 函数不起作用,因为变量和命名空间没有实现clojure.lang.Named。)
问题文本中的函数也很好,尽管最好从命名空间中提取符号名称 -- (.-name (get ...)) -- 而不是通过使用 @ 来依赖命名空间的 toString 表示987654336@.
您可能还想添加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)))
或者在 Clojure 1.4 及更早版本中使用一些 if-lets。