请在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规范不包括自动解析的关键词。

by
谢谢,我以为是这样,但不知何故我能够重现这个问题,我会深入了解并找到问题所在后再次提出。

谢谢,

Timo
+1
by
编辑 by

自动命名空间的键在读取时扩展为普通的命名空间键,因此一旦它们存在于数据结构中,它们就会被打印出命名空间

$ 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

by
编辑 by
(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会评估字符串并正确解析关键字,但它会打开安全问题,因此不应使用。
by
哦,那就是发生的事情。你所观察到的,clojure 允许你构造那些打印出来时不可读的关键字。
`(keyword ":out")`构造了一个没有任何命名空间,名称为`":out"`的关键字,因此当它以`"::out"`打印时,它并不是打印为"自动命名空间",它只是打印出它的名称(":out")在冒号":"后,将它识别为关键字。你可以从字符串中自由地构造关键字。
`(keyword "heh [{:a 1}]" "//::! :: ::")`会产生一个命名空间为`"heh [{:a 1}]"`、名称为`"//::! :: ::"`的关键字,它被打印为`:heh [{:a 1}]///::! :: ::`。

由于在你的情况下无法清除你的数据,我建议使用edn以外的允许为不同类型提供自定义读取器和写入器的序列化。例如,看看[transit]()。
...