如何正确地将Clojure命名空间关键字转换为字符串?

18

当使用name函数时,它会正确地返回关键字的名称作为字符串,例如:

(name :k) ; => "k"

当在命名空间关键字上使用 name 时会出现问题,例如:

A problem exists when using name on a namespaced keyword such as:

(name :n/k) ; => "k"

我可以使用 命名空间 函数来正确获取我需要的字符串:

(str (namespace :n/k) "/" (name :n/k)) ; => "n/k"

但是出于某些原因,我觉得应该有更好的方法来获取完全限定的字符串。

最好的方法是什么?

4个回答

12

关键字实际上在公共终态字段中存储具有相同名称空间和名称的符号,并通过在该符号的字符串表示前加冒号来生成其字符串表示形式。因此,我们可以直接请求该符号,而不是在其前面添加冒号:

(str (.-sym :foo/bar))
;= "foo/bar"

这种方法对我来说比(.substring (str :foo/bar) 1)快得多,分别是4.7纳秒和14纳秒。 - nivekuil
1
为了代码的美观,您也可以在Clojure 1.11中使用symbol函数:(str (symbol :foo/bar)) - JovanToroman

7

您的做法是最好的方法;之所以难,是因为将命名空间关键字转换为字符串是一个不太常见的目标,也不是您经常需要做的事情。如果您愿意,您可以在不重复关键字的情况下编写它:

(string/join "/" ((juxt namespace name) k))

我知道,在这种特殊情况下,我有一些MIME类型,例如:text/plain,需要在将它们放到网络上之前进行字符串化。因此,它们并不完全是Clojure命名空间。 - guilespi

7
(subs (str :foo/k) 1)
;=> "foo/k"

0

基于name的实现:

user=> (source name)
(defn name
  "Returns the name String of a string, symbol or keyword."
  {:tag String
   :added "1.0"
   :static true}
  [x]
  (if (string? x) x (. ^clojure.lang.Named x (getName))))
nil
user=>

考虑到 clojure.lang.Named 接口有一个 getNamespace 方法:

https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Named.java

你可以这样做:

(defn full-name [k] (str (.getNamespace k) "/" (.getName k)))

在ClojureScript中呢? - Mnebuerquo
有内置函数可以实现这个功能 - (namespace :foo/bar) -> "foo", 和 (name :foo/bar) -> "bar" - August Lilleaas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接