go笔记--json包使用
@
json包实现了json对象的编解码,参见rfc 4627。json对象和go类型的映射关系主要通过marshal和unmarshal函数实现
marshal
func marshal(v interface{}) ([]byte, error)
marshal函数返回v的json编码。
marshal函数会递归的处理值。如果一个值实现了marshaler接口切非nil指针,会调用其marshaljson方法来生成json编码。nil指针异常并不是严格必需的,但会模拟与unmarshaljson的行为类似的必需的异常。
否则,marshal函数使用下面的基于类型的默认编码格式:
布尔类型编码为json布尔类型。
浮点数、整数和number类型的值编码为json数字类型。
字符串编码为json字符串。角括号"<"和">"会转义为"\u003c"和"\u003e"以避免某些浏览器吧json输出错误理解为html。基于同样的原因,"&"转义为"\u0026"。
数组和切片类型的值编码为json数组,但[]byte编码为base64编码字符串,nil切片编码为null。
结构体的值编码为json对象。每一个导出字段变成该对象的一个成员,除非:
- 字段的标签是"-"
- 字段是空值,而其标签指定了omitempty选项
空值是false、0、""、nil指针、nil接口、长度为0的数组、切片、映射。对象默认键字符串是结构体的字段名,但可以在结构体字段的标签里指定。结构体标签值里的"json"键为键名,后跟可选的逗号和选项,举例如下:
// 字段被本包忽略
field int json:"-"
// 字段在json里的键为"myname"
field int json:"myname"
// 字段在json里的键为"myname"且如果字段为空值将在对象中省略掉
field int json:"myname,omitempty"
// 字段在json里的键为"field"(默认值),但如果字段为空值会跳过;注意前导的逗号
field int json:",omitempty"
"string"选项标记一个字段在编码json时应编码为字符串。它只适用于字符串、浮点数、整数类型的字段。这个额外水平的编码选项有时候会用于和javascript程序交互:
int64string int64 json:",string"
如果键名是只含有unicode字符、数字、美元符号、百分号、连字符、下划线和斜杠的非空字符串,将使用它代替字段名。
匿名的结构体字段一般序列化为他们内部的导出字段就好像位于外层结构体中一样。如果一个匿名结构体字段的标签给其提供了键名,则会使用键名代替字段名,而不视为匿名。
go结构体字段的可视性规则用于供json决定那个字段应该序列化或反序列化时是经过修正了的。如果同一层次有多个(匿名)字段且该层次是最小嵌套的(嵌套层次则使用默认go规则),会应用如下额外规则:
1)json标签为"-"的匿名字段强行忽略,不作考虑;
2)json标签提供了键名的匿名字段,视为非匿名字段;
3)其余字段中如果只有一个匿名字段,则使用该字段;
4)其余字段中如果有多个匿名字段,但压平后不会出现冲突,所有匿名字段压平;
5)其余字段中如果有多个匿名字段,但压平后出现冲突,全部忽略,不产生错误。
对匿名结构体字段的管理是从go1.1开始的,在之前的版本,匿名字段会直接忽略掉。
映射类型的值编码为json对象。映射的键必须是字符串,对象的键直接使用映射的键。
指针类型的值编码为其指向的值(的json编码)。nil指针编码为null。
接口类型的值编码为接口内保持的具体类型的值(的json编码)。nil接口编码为null。
通道、复数、函数类型的值不能编码进json。尝试编码它们会导致marshal函数返回unsupportedtypeerror。
json不能表示循环的数据结构,将一个循环的结构提供给marshal函数会导致无休止的循环。
example
func json_encode() { type colorgroup struct { id int name string colors []string } group := colorgroup{ id: 1, name: "reds", colors: []string{"crimson", "red", "ruby", "maroon"}, } b, err := json.marshal(group) if err != nil { fmt.println("error:", err) os.exit(1) } os.stdout.write(b) }
unmarshal
func unmarshal(data []byte, v interface{}) error
unmarshal函数解析json编码的数据并将结果存入v指向的值。
unmarshal和marshal做相反的操作,必要时申请映射、切片或指针,有如下的附加规则:
要将json数据解码写入一个指针,unmarshal函数首先处理json数据是json字面值null的情况。此时,函数将指针设为nil;否则,函数将json数据解码写入指针指向的值;如果指针本身是nil,函数会先申请一个值并使指针指向它。
要将json数据解码写入一个结构体,函数会匹配输入对象的键和marshal使用的键(结构体字段名或者它的标签指定的键名),优先选择精确的匹配,但也接受大小写不敏感的匹配。
要将json数据解码写入一个接口类型值,函数会将数据解码为如下类型写入接口:
bool 对应json布尔类型
float64 对应json数字类型
string 对应json字符串类型
[]interface{} 对应json数组
map[string]interface{} 对应json对象
nil 对应json的null
如果一个json值不匹配给出的目标类型,或者如果一个json数字写入目标类型时溢出,unmarshal函数会跳过该字段并尽量完成其余的解码操作。如果没有出现更加严重的错误,本函数会返回一个描述第一个此类错误的详细信息的unmarshaltypeerror。
json的null值解码为go的接口、指针、切片时会将它们设为nil,因为null在json里一般表示“不存在”。 解码json的null值到其他go类型时,不会造成任何改变,也不会产生错误。
当解码字符串时,不合法的utf-8或utf-16代理(字符)对不视为错误,而是将非法字符替换为unicode字符u+fffd。
func json_decode() { type colorgroup struct { id int name string colors []string } group := colorgroup{ id: 1, name: "reds", colors: []string{"crimson", "red", "ruby", "maroon"}, } b, err := json.marshal(group) if err != nil { fmt.println("error:", err) } r := colorgroup{} err = json.unmarshal(b, &r) if err != nil { fmt.println("json.unmarshal error : ", err) os.exit(1) } fmt.println(r) }
处理json对象
json对象 通过 map[string]interface{} 表示
func json_struct_and_map() { type people struct { name string `json:"name"` age int `json:"age"` feature map[string]interface{} `json:feature` } var feature map[string]interface{} = make(map[string]interface{}) feature["personality"] = "cute" feature["inner"] = "strength" p := people { name : "ailumiyana", age : 18, feature : feature, } b, err := json.marshal(p) if err != nil { fmt.println("error:", err) os.exit(1) } fmt.println("encode : ") os.stdout.write(b) r := people{} err = json.unmarshal(b, &r) if err != nil { fmt.println("json.unmarshal error : ", err) os.exit(1) } fmt.println("\ndecode : ") fmt.println(r) //update if r.feature == nil { r.feature = make(map[string]interface{}) } r.feature["fea"] = "warmth" b, err = json.marshal(r) if err != nil { fmt.println("error:", err) os.exit(1) } fmt.println("update : ") os.stdout.write(b) }
完整示例 :
package main import( "encoding/json" "fmt" "os" ) func json_encode() { type colorgroup struct { id int name string colors []string } group := colorgroup{ id: 1, name: "reds", colors: []string{"crimson", "red", "ruby", "maroon"}, } b, err := json.marshal(group) if err != nil { fmt.println("error:", err) os.exit(1) } os.stdout.write(b) } func json_decode() { type colorgroup struct { id int name string colors []string } group := colorgroup{ id: 1, name: "reds", colors: []string{"crimson", "red", "ruby", "maroon"}, } b, err := json.marshal(group) if err != nil { fmt.println("error:", err) } r := colorgroup{} err = json.unmarshal(b, &r) if err != nil { fmt.println("json.unmarshal error : ", err) os.exit(1) } fmt.println(r) } func json_struct_and_map() { type people struct { name string `json:"name"` age int `json:"age"` feature map[string]interface{} `json:feature` } var feature map[string]interface{} = make(map[string]interface{}) feature["personality"] = "cute" feature["inner"] = "strength" p := people { name : "ailumiyana", age : 18, feature : feature, } b, err := json.marshal(p) if err != nil { fmt.println("error:", err) os.exit(1) } fmt.println("encode : ") os.stdout.write(b) r := people{} err = json.unmarshal(b, &r) if err != nil { fmt.println("json.unmarshal error : ", err) os.exit(1) } fmt.println("\ndecode : ") fmt.println(r) //update if r.feature == nil { r.feature = make(map[string]interface{}) } r.feature["fea"] = "warmth" b, err = json.marshal(r) if err != nil { fmt.println("error:", err) os.exit(1) } fmt.println("update : ") os.stdout.write(b) } func main(){ json_encode() json_decode() json_struct_and_map() }