这将有助于澄清正在发生的事情。我们首先包含一个有用的库:
(ns tst.demo.core
(:use tupelo.core tupelo.test)
(:require
[tupelo.core :as t]
[tupelo.string :as str]
))
为了避免双引号对文字字符串和嵌入字符串的歧义,我们使用单引号编写源 JSON,然后使用辅助函数str/quotes->double
将字符串中的每个单引号转换为双引号. 否则,我们可以从文件中读取源 JSON(而不是内联)。
(def json-str
(str/quotes->double
"{
'Data': [
{
'Metadata': {
'Series': '1/2'
},
'Hybrid': {
'Foo': 76308,
'Bar': '76308',
'Cat': 'Foo123'
}
}
],
'Footer': {
'Count': 3,
'Age': 0
}
} "))
我们首先将 json字符串转换为 EDN数据结构(不是字符串)。然后我们将 EDN 数据结构转换为EDN 字符串。输出(println
和prn
)说明了差异:
(dotest
(let [edn-data (t/json->edn json-str) ; JSON string => EDN data
edn-str (pr-str edn-data) ; EDN data => EDN string
]
(newline)
(println "edn-data =>")
(spy-pretty edn-data) ; uses 'prn'
(newline)
(println "edn-str (println) =>")
(println edn-str)
(newline)
(println "edn-str (prn) =>")
(prn edn-str)))
结果:
------------------------------------------
Clojure 1.10.2-alpha1 Java 14.0.1
------------------------------------------
Testing tst.demo.core
edn-data =>
{:Data
[{:Metadata {:Series "1/2"},
:Hybrid {:Foo 76308, :Bar "76308", :Cat "Foo123"}}],
:Footer {:Count 3, :Age 0}}
edn-str (println) =>
{:Data [{:Metadata {:Series "1/2"}, :Hybrid {:Foo 76308, :Bar "76308", :Cat "Foo123"}}], :Footer {:Count 3, :Age 0}}
edn-str (prn) =>
"{:Data [{:Metadata {:Series \"1/2\"}, :Hybrid {:Foo 76308, :Bar \"76308\", :Cat \"Foo123\"}}], :Footer {:Count 3, :Age 0}}"
仔细想想什么是数据结构,什么是字符串。如果我们写入[1 :b "hi"]
Clojure 源文件,Clojure Reader 会创建一个数据结构,它是一个包含 int、关键字和字符串的 3 元素向量。如果我们使用 将其转换为字符串str
,则输出只是一个 11 个字符的字符串,而不是数据结构。
但是,如果我们想将该字符串(双引号内)粘贴到源文件中,我们不仅需要外部双引号来标记字符串的开头和结尾,还需要字符串内的每个双引号(例如作为"hi"
) 的一部分需要转义,因此 Clojure 阅读器可以判断它们属于字符串内部,并且不标记字符串的开头或结尾。
适应所有不同的模式需要一段时间!
Clojure 阅读器与编译器
Clojure 源代码文件分两遍处理。
Clojure Reader 获取每个源文件的文本(多行的巨大字符串)并将其转换为数据结构。
Clojure 编译器从 (1) 中获取数据结构并输出 Java 字节码。