一种方法是在常见的键的基础上,定义自定义产品语义类型,并加入额外的键。
https://github.com/cognitect/transit-format#extensibility
通过这种方法,您可以节省一些空间,但可能需要付出一些维护工作以及额外的CPU时间(这对于您一次处理多个 smirk 文档可能是可接受的)。
以下是一个仅用 Product 包装产品映射的示例,这样就不必在代码库的其余部分使用记录。
(ns foo
(:require
[cognitect.transit :as tr])
(:import
[com.cognitect.transit WriteHandler]
[java.io ByteArrayOutputStream]))
(defrecord Product [m])
(def product-tag "pro")
(def common-keys [:product/foo :product/bar :product/baz])
(def custom-writers
{Product (reify WriteHandler
(getVerboseHandler [_] nil)
(stringRep [_ kw] nil)
(tag [_ _] product-tag)
(rep [_ p] (let [common (mapv (:m p) common-keys)
custom (reduce dissoc (:m p) common-keys)]
(into [custom] common))))})
(def custom-readers
{product-tag (fn [rep]
(let [[m & common-vals] rep]
(merge m (zipmap common-keys common-vals))))})
(defn write [writers product]
(let [out (ByteArrayOutputStream. 4096)
wr (tr/writer out :json writers)]
(tr/write wr product)
(.toString out)))
(write {:handlers custom-writers}
(Product. {:product/foo 1 :product/bar 2 :product/baz 3 :custom/foo 4}))
;; "[\"~#pro\",[[\"^ \",\"~:custom/foo\",4],1,2,3]]"
(write {}
(Product. {:product/foo 1 :product/bar 2 :product/baz 3 :custom/foo 4}))
;; "[\"^ \",\"~:m\",[\"^ \",\"~:product/foo\",1,\"~:product/bar\",2,\"~:product/baz\",3,\"~:custom/foo\",4]]"
(write {}
{:product/foo 1 :product/bar 2 :product/baz 3 :custom/foo 4})
;; "[\"^ \",\"~:product/foo\",1,\"~:product/bar\",2,\"~:product/baz\",3,\"~:custom/foo\",4]"