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