Как я могу использовать *data-reader * с edn?
Я пытался следовать документации для clojure.instant/read-instant-timestamp
, который гласит:
clojure.instant / чтения мгновенного Отметка времени Чтобы прочитать момент как java.sql.Timestamp, свяжите *data-reader * с map с этим var в качестве значения для ключа 'inst. Отметка времени сохраняет доли секунды с наносекундной точностью. Смещение часового пояса будет использоваться для конвертации в 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.
2 ответа
*data-readers*
динамическая переменная, кажется, относится к read-string
а также 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)))
Просмотр исходного кода для clojure.edn
Читатель здесь, я не мог найти ничего, что указывало бы на то же *data-readers*
там вообще используется вар.
clojure.core
функции read
а также read-string
использование LispReader
(который использует значение из *data-readers*
), а функции из clojure.edn
использовать EdnReader
,
это edn
библиотека является относительно новым в Clojure, поэтому это может быть причиной того, что строка документации недостаточно конкретна edn
против core
читатель, который может вызвать такую путаницу.
Надеюсь, поможет.
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*} "...")
(Следующий раздел добавлен в ответ на комментарии Ричарда Мона в ветке комментариев к этой проблеме GitHub. Непосредственный вопрос: уместно ли вызывать функцию читателя eval
на переданных данных. Я не связан с данным проектом; пожалуйста, смотрите билет для деталей, а также комментарии Ричарда к настоящему ответу.)
Стоит добавить, что *data-readers*
неявно заселен из любого data_readers.{clj,cljc}
файлы, которые Clojure находит в корне пути к классам во время запуска. Это может быть удобно (это позволяет использовать пользовательские теговые литералы в исходном коде Clojure и в REPL), но это означает, что новые читатели данных могут появляться там с изменением одной зависимости. Используя явно построенную карту читателя с clojure.edn
это простой способ избежать неожиданностей (что может быть особенно неприятно при работе с ненадежным вводом).
(Обратите внимание, что неявный процесс загрузки не приводит к немедленной загрузке какого-либо кода или даже к тегу, указанному в *data-readers*
впервые встречается; процесс, который заполняет *data-readers*
создает пустые пространства имен с несвязанными Vars в качестве заполнителей, и для фактического использования этих читателей нужно еще require
соответствующие пространства имен в коде пользователя.)