我尝试按照clojure.instant/read-instant-timestamp
的文档进行操作,其中包含:
clojure.instant/read-instant-timestamp To read an instant as a java.sql.Timestamp, bind *data-readers* to a map with this var as the value for the 'inst key. Timestamp preserves fractional seconds with nanosecond precision. The timezone offset will be used to convert into UTC.`
以下结果出乎意料:
(do
(require '[clojure.edn :as edn])
(require '[clojure.instant :refer [read-instant-timestamp]])
(let [instant "#inst \"1970-01-01T00:00:09.999-00:00\""
reader-map {'inst #'read-instant-timestamp}]
;; This binding is not appearing to do anything.
(binding [*data-readers* reader-map]
;; prints java.util.Date -- unexpected
(->> instant edn/read-string class println)
;; prints java.sql.Timestamp -- as desired
(->> instant (edn/read-string {:readers reader-map}) class println))))
如何使用*data-readers*
绑定? Clojure版本1.5.1。
答案 0 :(得分:12)
clojure.edn
函数仅使用存储在clojure.core/default-data-readers
中的数据读取器,从Clojure 1.5.1开始,它为读者提供即时和UUID文字。如果您想使用自定义阅读器,可以通过传递:readers
选项来实现;特别是,你可以传递*data-readers*
。这在clojure.edn/read
的文档字符串中有记录(clojure.edn/read-string
的文档字符串引用read
的文档字符串。)
以下是一些例子:
(require '[clojure.edn :as edn])
;; instant literals work out of the box:
(edn/read-string "#inst \"2013-06-08T01:00:00Z\"")
;= #inst "2013-06-08T01:00:00.000-00:00"
;; custom literals can be passed in in the opts map:
(edn/read-string {:readers {'foo identity}} "#foo :asdf")
;= :asdf
;; use current binding of *data-readers*
(edn/read-string {:readers *data-readers*} "...")
(以下部分是为了回应Richard Möhn在this GitHub issue的评论主题中所做的评论。当前的问题是读者函数是否适合调用{{ 1}}关于传入的数据。我不参与相关项目;请查看详细信息,以及理查德对目前答案的评论。)
值得补充的是,eval
是从Clojure在启动时在类路径的根目录中找到的任何*data-readers*
文件中隐式填充的。这可能很方便(它允许在Clojure源代码和REPL中使用自定义标记文字),但它确实意味着新数据读取器可能会出现在那里,并且单个依赖项发生了更改。使用明确构造的带有data_readers.{clj,cljc}
的读者地图是一种避免意外的简单方法(在处理不受信任的输入时可能会特别讨厌)。
(请注意,隐式加载进程不会导致任何代码被立即加载,或者甚至在第一次遇到clojure.edn
中提到的标记时;填充{{1使用未绑定的Vars创建空命名空间作为占位符,并且实际使用这些读者仍需要*data-readers*
用户代码中的相关命名空间。)
答案 1 :(得分:5)
*data-readers*
动态变量似乎仅适用于来自read-string
的{{1}}和read
函数。
clojure.core
浏览(require '[clojure.instant :refer [read-instant-timestamp]])
(let [instant "#inst \"1970-01-01T00:00:09.999-00:00\""
reader-map {'inst #'read-instant-timestamp}]
;; This will read a java.util.Date
(->> instant read-string class println)
;; This will read a java.sql.Timestamp
(binding [*data-readers* reader-map]
(->> instant read-string class println)))
阅读器here的源代码时,我找不到任何可能表明在那里使用相同clojure.edn
var的内容。
*data-readers*
的函数read
和read-string
使用LispReader
(使用clojure.core
中的值),而来自*data-readers*
的函数使用EdnReader
。
此clojure.edn
库在Clojure中相对较新,因此可能是文档字符串对于edn
与edn
读者不够具体的原因,这可能导致此类混乱。
希望它有所帮助。