狗好看の世界

Less words, more attempting.

自定义EDN的reader function

Table of Contents

需求

有时需要在EDN的数据结构中, 写一些自定义的类型. 如果使用 (:some-type x) 或者 [:some-tye x], 不好处理. 理想的情况是我们读取到数据的时候, 直接将其转换成对应的类型. 而不是用传统的方式, 先将数据处理成普通的数据结构, 再逐步处理特定的部分.

解决方案

使用自定义的 reader function. 假设我们接受的数据结构(EDN字符串)如下:

[{:name "Dog.LooksGood"
  :age 18}
 {:name "Foo.Bar"
  :age 16}]

我们希望得到

[{:name {:first "Dog"
         :last "LooksGood"}
  :age 18}
 {:name {:first "Foo"
         :last "Bar"}
  :age 16}]

首先, 我们自定义一个标签 #name 来标识一种特殊的数据处理方式. 接受的数据应该应该为

[{:name #name "Dog.LooksGood"
    :age 18}
   {:name #name "Foo.Bar"
    :age 16}]

使用 clojure.edn/read-string 的时候, 传入自定义reader function.

(require '[clojure.edn :as edn])

;; EDN数据
(def edn-string
  "[{:name #name \"Dog.LooksGood\"
      :age 18}
     {:name #name \"Foo.Bar\"
      :age 16}]")

;; 自定义reader
(defn parse-name [name]
  (let [[f l] (clojure.string/split name #"\.")]
    {:first f
     :last l}))

(edn/read-string
  {:readers {'name parse-name}}
  edn-string)
;; =>[{:name {:first "Dog", :last "LooksGood"}, :age 18} {:name {:first "Foo", :last "Bar"}, :age 16}]

Comments