请在2024年Clojure调查!中分享您的想法。

欢迎!请参阅关于页面以获取更多有关此功能的信息。

0
命名空间和变量
编辑

我正在使用pr-str序列化一个可能包含具有自动命名空间的关键字的数据结构。

我希望在序列化之前减少数据结构,使其不包含自动关键字,但不知道如何检测它?

(def x ::outbound)

(pr-str x) => "::outbound"

(edn/read-string "::outbound") => exception

(namespace x) => "current-namespace" 

那么,有没有办法知道x是否有自动命名空间?

谢谢,

抱歉 - 未在repl上运行即写了这个问题 - 这里有一个合适的例子。

(keyword ":out") => ::out

(pr-str (keyword ":out")) => "::out"

(edn/read-string (pr-str (keyword ":out"))) =>

Execution error at user/eval93457 (form-init751239350220000799.clj:1).
Invalid token: ::out

2 个答案

+2

自动解析的命名空间不是关键字的属性。关键字只有命名空间和名称。自动解析的 (::) 关键字会在读取时解析为带有命名空间的完全限定关键字。Clojure打印机永远不会打印带有 :: 的关键字。

如果您想自定义打印机或使用其他函数来检测关键字命名空间与当前命名空间相同,并将其打印为自动解析关键字,这是可能的(但几乎肯定不是一个很好的主意)。

edn/read-string不会读取自动解析的关键字,因为edn规范不包括自动解析关键字。

谢谢,我想到了,但不知何故我能够复现这个问题,我会深入调查并一旦找到原因再提问。

谢谢。

Timo
+1

编辑

自动命名空间的关键字在读取时扩展为普通命名空间的关键字,因此一旦你在数据结构中拥有它们,它们就会带有命名空间打印出来。

$ clj
Clojure 1.10.0
user=> (pr-str ::out)
":user/out"

你是如何让(pr-str ::out)打印出::out的?

编辑
你所观察到的,事实上是Clojure 允许你构建在打印时不可读的关键字。
(keyword ":out")构建了一个没有命名空间,名称为":out"的关键字,因此当它被按"::out"打印时,并不是它按照“自动命名空间”打印,它只是在冒号":"之后打印了它的名称(":out"),冒号":"用以标识它为关键字。你可以从字符串构造任意关键字。
(keyword "heh [{:a 1}]" "//::! :: ::")将产生一个命名空间为"heh [{:a 1}]",名称为"//::! :: ::"的关键字,它将按如下方式打印::heh [{:a 1}]///::! :: ::

由于在你的情况下没有清除数据的方法,我建议你使用允许为不同类型自定义读取器和编写器的序列化方式,而不是使用EDN。例如,可以查看transit


编辑
(keyword ":out") => ::out

(pr-str (keyword ":out")) => "::out"

(edn/read-string (pr-str (keyword ":out"))) =>

用户/eval93457 (form-init751239350220000799.clj:1)中发生执行错误。
无效的令牌: ::out

显然在我们这个例子中,输入是动态的——我们当前的问题是它在 Datomic 历史记录中存储着,无法删除——因此我们需要一种方法来修正序列化或反序列化。

clojure.core/read-string 正确解析字符串并解析关键字,但它会打开安全问题,因此不应该使用
哦,这是发生的事情。你所观察到的就是 Clojure 允许你构建无法打印的名称关键字。
`(keyword ":out")` 构造一个没有名称空间且名称为 `:out` 的关键字,因此当它以 `"::out"` 打印时,它不是“自动命名空间”,它只是在其名称(`:out`)后打印冒号 “:” 来识别它是一个关键字。你可以随意从字符串构建关键字。
`(keyword "heh [{:a 1}]" "//::! :: ::")` 将会产生一个具有名称空间 `"heh [{:a 1}]"` 和名称 `"//::! :: ::"` 的关键字,它打印为 `:heh [{:a 1}]///::! :: ::`。

由于在你的情况下无法清理你的数据,我建议使用支持不同类型自定义读取器和编写器的序列化方法,而不是 edn。例如,查阅 [transit](https://github.com/cognitect/transit-clj)。
...