@@ -2,20 +2,20 @@
数据结构要在网络中传输或保存到文件, 就必须对其编码和解码; 目前存在很多编码格式: JSON, XML, gob, Google 缓冲协议等等。Go 语言支持所有这些编码格式;在后面的章节,我们将讨论前三种格式。
结构能够 包含二进制数据,如果作为文本打印,那么可读性是很差的。另外结构内部包含命 名字段,所以 不清楚数据的用意。
结构可 能包含二进制数据,如果将其 作为文本打印,那么可读性是很差的。另外结构内部可能 包含匿 名字段,而 不清楚数据的用意。
通过把数据转换成纯文本,使用命名的字段来标注,让其具有可读性。这样的数据格式可以通过网络传输,而且是与平台无关的,任何类型的应用都能够读取和输出,不用关系 操作系统和编程语言的类型。
通过把数据转换成纯文本,使用命名的字段来标注,让其具有可读性。这样的数据格式可以通过网络传输,而且是与平台无关的,任何类型的应用都能够读取和输出,不与 操作系统和编程语言的类型相关 。
下面是一些术语说明:
- 数据结构 --> 指定格式 = `序列化` 或 `编码` ( 传输之前)
- 指定格式 --> 数据格式 = `反序列化` 或 `解码` ( 传输之后)
- 数据结构 --> 指定格式 = `序列化` 或 `编码` ( 传输之前)
- 指定格式 --> 数据格式 = `反序列化` 或 `解码` ( 传输之后)
序列化是在内存中把数据转换成指定格式( data -> string), 反之亦然( string -> data structure)
序列化是在内存中把数据转换成指定格式( data -> string) , 反之亦然( string -> data structure)
编码也是一样的,只是输出一个数据流(实现了 io.Writer 接口);解码是从一个数据流(实现了 io.Reader) 输出到一个数据结构。
我们都比较熟悉XML格式(参阅12.10); 但有些时候JSON( JavaScript Object Notation, 参阅 [http://json.org ](http://json.org )) 被作为首选,主要是由于其格式上非常简洁。通常json被用在 web后端和浏览器之间通讯, 但是在其它场景也同样的有用。
我们都比较熟悉 XML 格式(参阅 [ 12.10 ](12.9.md ) );但有些时候 JSON( JavaScript Object Notation, 参阅 [http://json.org ](http://json.org )) 被作为首选,主要是由于其格式上非常简洁。通常 JSON 被用于 web 后端和浏览器之间的 通讯,但是在其它场景也同样的有用。
这是一个简短的 JSON 片段:
@@ -28,11 +28,11 @@
}
```
尽管XML被广泛的应用, 但是JSON更加简洁、轻量(其 占用更少的内存、磁盘及网络带宽) 和更好的可读性,这也说明他 越来越受欢迎。
尽管 XML 被广泛的应用,但是 JSON 更加简洁、轻量( 占用更少的内存、磁盘及网络带宽) 和更好的可读性,这也说明它 越来越受欢迎。
go 语言的json包可以让你在程序中方便的读取和写入JSON数据。
Go 语言的 json 包可以让你在程序中方便的读取和写入 JSON 数据。
我们将在下面的例子里使用json包, 并使用练习10.1 vcard.go中一个简化版本的Address和 VCard结构( 为了简单起见, 我们忽略了很多错误处理, 不过在实际应用中你必须要合理的处理这些错误, 参阅13章)
我们将在下面的例子里使用 json 包,并使用练习 10.1 vcard.go 中一个简化版本的 Address 和 VCard 结构( 为了简单起见,我们忽略了很多错误处理,不过在实际应用中你必须要合理的处理这些错误,参阅 13 章)
示例 12.16 [json.go ](examples/chapter_12/json.go ):
@@ -81,7 +81,7 @@ func main() {
```
`json.Marshal()` 的函数签名是 `func Marshal(v interface{}) ([]byte, error)` , 下面是数据编码后的json 文本( 实际上是一个[]bytes):
`json.Marshal()` 的函数签名是 `func Marshal(v interface{}) ([]byte, error)` , 下面是数据编码后的 JSON 文本( 实际上是一个 []bytes) :
```javascript
{
@@ -100,35 +100,35 @@ func main() {
}
```
处 于安全考虑, 在web应用中最好使用`json.MarshalforHTML()` 函数, 其对数据执行HTML转码, 所以文本会 被安全的 嵌在HTML`<script>` 标签中。
出 于安全考虑,在 web 应用中最好使用 `json.MarshalforHTML()` 函数, 其对数据执行HTML转码, 所以文本可以 被安全地 嵌在 HTML `<script>` 标签中。
JSON与go 类型对应如下:
JSON 与 Go 类型对应如下:
- bool 对应 JSON 的 booleans
- float64 对应 JSON 的 numbers
- string 对应 JSON 的 strings
- nil 对应 JSON 的 null
不是所有的数据都可以编码为json 类型:只有验证通过的数据结构才能被编码:
不是所有的数据都可以编码为 JSON 类型:只有验证通过的数据结构才能被编码:
- JSON对象只支持字符串类型的key; 要编码一个g o map类型, map必须是map[string]T( T是json包中支持的任何类型)
- JSON 对象只支持字符串类型的 key; 要编码一个 G o map 类型, map 必须是 map[string]T( T是 ` json` 包中支持的任何类型)
- Channel, 复杂类型和函数类型不能被编码
- 不支持循环数据结构;它将引起序列化进入一个无线 循环
- 指针可以被编码,实际上是对指针指向的值进行编码( 或者指针是nil)
- 不支持循环数据结构;它将引起序列化进入一个无限 循环
- 指针可以被编码,实际上是对指针指向的值进行编码( 或者指针是 nil)
### 反序列化:
`UnMarshal()` 的函数签名是 `func Unmarshal(data []byte, v interface{}) error` 把json 解码为数据结构。
`UnMarshal()` 的函数签名是 `func Unmarshal(data []byte, v interface{}) error` 把 JSON 解码为数据结构。
我们首先创建一个结构Message用来保存解码的数据: `var m Message` 并调用`Unmarshal()` ,解析[]byte中的json 数据并将结果存入指针m 指向的值
我们首先创建一个结构 Message 用来保存解码的数据:`var m Message` 并调用 `Unmarshal()` ,解析 []byte 中的 JSON 数据并将结果存入指针 m 指向的值
虽然反射能够让json 字段去尝试匹配目标结构字段;但是只有真正匹配上的字段才会填充数据。字段没有匹配不会报错,而是直接忽略掉。
虽然反射能够让 JSON 字段去尝试匹配目标结构字段;但是只有真正匹配上的字段才会填充数据。字段没有匹配不会报错,而是直接忽略掉。
( 练习15.2b twitter_status_json.go中用到了UnMarshal)
( 练习 15.2b twitter_status_json.go 中用到了 UnMarshal)
### 解码任意的数据:
json包使用map[string]interface{}和 []interface{}储存任意的JSON对象和数组; 其可以被反序列化为任何的JSON blob存储到接口值中。
json 包使用 ` map[string]interface{}` 和 ` []interface{}` 储存任意的 JSON 对象和数组;其可以被反序列化为任何的 JSON blob 存储到接口值中。
来看这个 JSON 数据,被存储在变量 b 中:
@@ -143,7 +143,7 @@ b == []byte({"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]})
err := json . Unmarshal ( b , & f )
```
f指向的值是一个map, key是一个字符串, value是自身存储作为空接口类型的值:
f 指向的值是一个 map, key 是一个字符串, value 是自身存储作为空接口类型的值:
```go
map [ string ] interface {} {
@@ -187,7 +187,7 @@ f指向的值是一个map,key是一个字符串, value是自身存储作为空
### 解码数据到结构:
如果我们事先知道json 数据,我们可以定义一个适当的结构并对json 数据反序列化。下面的例子中,我们将定义:
如果我们事先知道 JSON 数据,我们可以定义一个适当的结构并对 JSON 数据反序列化。下面的例子中,我们将定义:
```go
type FamilyMember struct {
@@ -205,24 +205,24 @@ type FamilyMember struct {
err := json . Unmarshal ( b , & m )
```
程序实际上是分配了一个新的切片。这是一个典型的反序列化引用类型( 指针、切片和映射) 的例子。
程序实际上是分配了一个新的切片。这是一个典型的反序列化引用类型( 指针、切片和 map) 的例子。
### 编码和解码流
json包提供Decoder和 Encoder类型来支持常用的读写 JSON数据流。NewDecoder和 NewEncoder函数分别封装了io.Reader和 io.Writer接口。
json 包提供 Decoder 和 Encoder 类型来支持常用 JSON 数据流读写 。NewDecoder 和 NewEncoder 函数分别封装了 io.Reader 和 io.Writer 接口。
```go
func NewDecoder ( r io . Reader ) * Decoder
func NewEncoder ( w io . Writer ) * Encoder
```
要想把json 直接写入文件, 可以使用json.NewEncoder初始化文件( 或者任何实现io.Writer的类型) , 并调用Encode(); 反过来与其对应的是使用json.Decoder和 Decode()函数:
要想把 JSON 直接写入文件,可以使用 json.NewEncoder 初始化文件( 或者任何实现 io.Writer 的类型) ,并调用 Encode();反过来与其对应的是使用 json.Decoder 和 Decode() 函数:
```go
func NewDecoder ( r io . Reader ) * Decoder
func ( dec * Decoder ) Decode ( v interface {}) error
```
来看下接口是如何对实现进行抽象的:数据结构可以是任何类型,只要其实现了某种接口,目标或来 源数据要能够被编码就必须实现io.Writer或 io.Reader接口。由于go 语言中到处都实现了Reader和 Writer, 因此Encoder和 Decoder可被应用的场景非常广泛, 例如读取或写入HTTP连接、websockets或文件。
来看下接口是如何对实现进行抽象的:数据结构可以是任何类型,只要其实现了某种接口,目标或源数据要能够被编码就必须实现 io.Writer 或 io.Reader 接口。由于 Go 语言中到处都实现了 Reader 和 Writer, 因此 Encoder 和 Decoder 可被应用的场景非常广泛,例如读取或写入 HTTP 连接、websockets 或文件。
## 链接