在 Clojure 中将已排序的映射保存+读取到文件

Jam*_*mes 5 clojure

我正在通过spit. 我希望我的地图中的一些地图被排序,并在我slurp将地图返回到我的程序时保持排序。排序映射没有唯一的文字表示,因此当我spit将映射映射到磁盘上时,排序映射和未排序映射的表示相同,并且#(read-string (slurp %))数据使每个映射成为通常的未排序类型。这是一个说明问题的玩具示例:

(def sorted-thing (sorted-map :c 3 :e 5 :a 1))
;= #'user/sorted-thing
(spit "disk" sorted-thing)
;= nil
(def read-thing (read-string (slurp "disk")))
;= #'user/read-thing

(assoc sorted-thing :b 2)
;= {:a 1, :b 2, :c 3, :e 5}
(assoc read-thing :b 2)
;= {:b 2, :a 1, :c 3, :e 5}
Run Code Online (Sandbox Code Playgroud)

有没有办法首先按排序读取地图,而不是在阅读后将它们转换为排序地图?或者这是我应该使用某种真实数据库的迹象?

Mic*_*zyk 4

动态可重新绑定的Var*print-dup*旨在支持此用例:

(binding [*print-dup* true]
  (prn (sorted-map :foo 1)))
; #=(clojure.lang.PersistentTreeMap/create {:foo 1})
Run Code Online (Sandbox Code Playgroud)

注释掉的行是打印的内容。

碰巧它也会影响str应用于 Clojure 数据结构,因此也会影响spit,所以如果你这样做

 (binding [*print-dup* true]
   (spit "foo.txt" (sorted-map :foo 1)))
Run Code Online (Sandbox Code Playgroud)

写入的地图表示foo.txt将是上面显示的地图表示。

诚然,我不能 100% 确定这是否在某个地方有记录;如果你对此感到不安,你总是可以使用withbound tospit的结果:pr-str*print-dup*true

(binding [*print-dup* true]
  (pr-str (sorted-map :foo 1)))
;= "#=(clojure.lang.PersistentTreeMap/create {:foo 1})"
Run Code Online (Sandbox Code Playgroud)

(这次最后一行是返回的值而不是打印输出。)

显然,您必须*read-eval*能够true读回这些文字。不过没关系,这正是它的目的(从可信来源读取代码)。