go json int转化string_[Go区块链基础]go JSON处理
JSON(JavaScript Object Notation)是一种比XML更轻量级的数据交换格式,在易于人们阅读和编写的同时,也易于程序解析和生成。尽管JSON是JavaScript的一个子集,但JSON采用完全独立于编程语言的文本格式,且表现为键/值对集合的文本描述形式(类似一些编程语言中的字典结构),这使它成为较为理想的、跨平台、跨语言的数据交换语言。开发者可以用JSON传输简单的字符串、
JSON(JavaScript Object Notation)是一种比XML更轻量级的数据交换格式,在易于人们阅读和编写的同时,也易于程序解析和生成。尽管JSON是JavaScript的一个子集,但JSON采用完全独立于编程语言的文本格式,且表现为键/值对集合的文本描述形式(类似一些编程语言中的字典结构),这使它成为较为理想的、跨平台、跨语言的数据交换语言。
开发者可以用JSON传输简单的字符串、数字、布尔值,也可以传输一个数组,或者一个更复杂的复合结构。在 Web 开发领域中, JSON被广泛应用于 Web 服务端程序和客户端之间的数据通信,但也不仅仅局限于此,其应用范围非常广阔,比如作为Web Services API输出的标准格式,又或是用作程序网络通信中的远程过程调用(RPC)等。
关于JSON的更多信息,请访问JSON官方网站http://json.org/ 查阅。
Go语言内建对JSON的支持。使用Go语言内置的encoding/json 标准库,开发者可以轻松使用Go程序生成和解析JSON格式的数据。在Go语言实现JSON的编码和解码时,遵循RFC4627协议标准。
1. 编码为JSON格式
使用json.Marshal()函数可以对一组数据进行JSON格式的编码。
json.Marshal()函数的声明如下:
func Marshal(v interface{}) ([]byte, error)
假如有如下一个Book类型的结构体:
type Book struct {
Title string
Authors []string
Publisher string
IsPublished bool
Price float
}
并且有如下一个Book类型的实例对象:
gobook := Book{
"Go区块链编程",
["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"ituring.com.cn",
true,
9.99
}
然后,我们可以使用json.Marshal()函数将gobook实例生成一段JSON格式的文本:
b, err := json.Marshal(gobook)
如果编码成功, err 将赋于零值 nil,变量b 将会是一个进行JSON格式化之后的[]byte类型:
b == []byte(`{
"Title": "Go区块链编程",
"Authors": ["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"Publisher": "ituring.com.cn",
"IsPublished": true,
"Price": 9.99
}`)
当我们调用json.Marshal(gobook)语句时,会递归遍历gobook对象,如果发现gobook这个数据结构实现了json.Marshaler接口且包含有效的值,Marshal()就会调用其MarshalJSON()方法将该数据结构生成 JSON 格式的文本。
Go语言的大多数数据类型都可以转化为有效的JSON文本,但channel、complex和函数这几种类型除外。
如果转化前的数据结构中出现指针,那么将会转化指针所指向的值,如果指针指向的是零值,那么null将作为转化后的结果输出。
在Go中, JSON转化前后的数据类型映射如下。
- 布尔值转化为JSON后还是布尔类型。
- 浮点数和整型会被转化为JSON里边的常规数字。
- 字符串将以UTF-8编码转化输出为Unicode字符集的字符串,特殊字符比如<将会被转义为 。
- 数组和切片会转化为JSON里边的数组,但[]byte类型的值将会被转化为 Base64 编码后的字符串, slice类型的零值会被转化为 null。
- 结构体会转化为JSON对象,并且只有结构体里边以大写字母开头的可被导出的字段才会被转化输出,而这些可导出的字段会作为JSON对象的字符串索引。
- 转化一个map类型的数据结构时,该数据的类型必须是 map[string]T(T可以是encoding/json 包支持的任意数据类型)。
2. 解码JSON数据
可以使用json.Unmarshal()函数将JSON格式的文本解码为Go里边预期的数据结构。
json.Unmarshal()函数的原型如下:
func Unmarshal(data []byte, v interface{}) error
该函数的第一个参数是输入,即JSON格式的文本(比特序列),第二个参数表示目标输出容器,用于存放解码后的值。要解码一段JSON数据,首先需要在Go中创建一个目标类型的实例对象,用于存放解码后的值:
var book Book
然后调用 json.Unmarshal() 函数,将 []byte 类型的JSON数据作为第一个参数传入,将 book 实例变量的指针作为第二个参数传入:
err := json.Unmarshal(b, &book)
如果 b 是一个有效的JSON数据并能和book结构对应起来,那么JSON解码后的值将会一一存放到book结构体中。解码成功后的 book 数据如下:
book := Book{
"Go区块链编程",
["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"ituring.com.cn",
true,
9.99
}
我们不禁好奇,Go是如何将JSON数据解码后的值一一准确无误地关联到一个数据结构中的相应字段呢?
实际上, json.Unmarshal()函数会根据一个约定的顺序查找目标结构中的字段,如果找到一个即发生匹配。假设一个JSON对象有个名为"Foo"的索引,要将"Foo"所对应的值填充到目标结构体的目标字段上, json.Unmarshal()将会遵循如下顺序进行查找匹配:
- 一个包含Foo标签的字段;
- 一个名为Foo的字段;
- 一个名为Foo或者Foo或者除了首字母其他字母不区分大小写的名为Foo的字段。
这些字段在类型声明中必须都是以大写字母开头、可被导出的字段。但是当JSON数据里边的结构和Go里边的目标类型的结构对不上时,会发生什么呢?示例代码如下:
b := []byte(`{"Title": "Go区块链编程", "Sales": 1000000}`)
var gobook Book
err := json.Unmarshal(b, &gobook)
如果JSON中的字段在Go目标类型中不存在,json.Unmarshal()函数在解码过程中会丢弃该字段。在上面的示例代码中,由于Sales字段并没有在Book类型中定义,所以会被忽略,只有Title这个字段的值才会被填充到gobook.Title中。
这个特性让我们可以从同一段JSON数据中筛选指定的值填充到多个Go语言类型中。当然,前提是已知JSON数据的字段结构。这也同样意味着,目标类型中不可被导出的私有字段(非首字母大写)将不会受到解码转化的影响。但如果JSON的数据结构是未知的,应该如何处理呢?
3. 解码未知结构的JSON数据
我们已经知道,Go语言支持接口。在Go语言里,接口是一组预定义方法的组合,任何一个类型均可通过实现接口预定义的方法来实现,且无需显示声明,所以没有任何方法的空接口可以代表任何类型。换句话说,每一个类型其实都至少实现了一个空接口。
Go内建这样灵活的类型系统,向我们传达了一个很有价值的信息:空接口是通用类型。如果要解码一段未知结构的JSON,只需将这段JSON数据解码输出到一个空接口即可。在解码JSON数据的过程中,JSON数据里边的元素类型将做如下转换:
- JSON中的布尔值将会转换为Go中的bool类型;
- 数值会被转换为Go中的float64类型;
- 字符串转换后还是string类型;
- JSON数组会转换为[]interface{}类型;
- JSON对象会转换为map[string]interface{}类型;
- null值会转换为nil。
在Go的标准库encoding/json包中,允许使用map[string]interface{}和[]interface{}类型的值来分别存放未知结构的JSON对象或数组,示例代码如下:
b := []byte(`{
"Title": "Go区块链编程",
"Authors": ["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"Publisher": "ituring.com.cn",
"IsPublished": true,
"Price": 9.99,
"Sales": 1000000
}`)
var r interface{}
err := json.Unmarshal(b, &r)
在上述代码中,r被定义为一个空接口。json.Unmarshal() 函数将一个JSON对象解码到空接口r中,最终r将会是一个键值对的map[string]interface{} 结构:
map[string]interface{}{
"Title": "Go区块链编程",
"Authors": ["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"Publisher": "ituring.com.cn",
"IsPublished": true,
"Price": 9.99,
"Sales": 1000000
}
要访问解码后的数据结构,需要先判断目标结构是否为预期的数据类型:
gobook, ok := r.(map[string]interface{})
然后,我们可以通过for循环搭配range语句一一访问解码后的目标数据:
if ok {
for k, v := range gobook {
switch v2 := v.(type) {
case string:
fmt.Println(k, "is string", v2)
case int:
fmt.Println(k, "is int", v2)
case bool:
fmt.Println(k, "is bool", v2)
case []interface{}:
fmt.Println(k, "is an array:")
for i, iv := range v2 {
fmt.Println(i, iv)
}
default:
fmt.Println(k, "is another type not handle yet")
}
}
}
虽然有些烦琐,但的确是一种解码未知结构的JSON数据的安全方式。
4. JSON的流式读写
Go内建的encoding/json包还提供Decoder和Encoder两个类型,用于支持JSON数据的流式读写,并提供NewDecoder()和NewEncoder()两个函数来便于具体实现:
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
代码清单5-6从标准输入流中读取JSON数据,然后将其解码,但只保留Title字段(书名),再写入到标准输出流中。
package main
import (
"encoding/json"
"log"
"os"
)
func main() {
dec := json.NewDecoder(os.Stdin)
enc := json.NewEncoder(os.Stdout)
for {
var v map[string]interface{}
if err := dec.Decode(&v); err != nil {
log.Println(err)
return
}
for k := range v {
if k != "Title" {
v[k] = nil, false
}
}
if err := enc.Encode(&v); err != nil {
log.Println(err)
}
}
}
使用Decoder 和Encoder对数据流进行处理可以应用得更为广泛些,比如读写HTTP连接、WebSocket或文件等,Go的标准库net/rpc/jsonrpc就是一个应用了Decoder和Encoder的实际例子。
更多推荐




所有评论(0)