go标准库的学习-encoding/json

参考https://studygolang.com/pkgdoc

 导入方式:

import "encoding/json"

json包实现了json对象的编解码,参见RFC 4627。Json对象和go类型的映射关系请参见Marshal和Unmarshal函数的文档。

参见"JSON and Go"获取本包的一个介绍:http://golang.org/doc/articles/json_and_go.html

 

 

func 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。

 

举例:通过interface{} 与 type assert的配合,这样就能够解析未知结构的JSON数了

package main 
import(
    "fmt"
    "encoding/json" ) func main() { var s interface{} str := ` { "name" : "testJSON", "servers" : [ { "serverName" : "Shanghai_VPN", "serverIP" : "127.0.0.1" }, { "serverName" : "Beijing_VPN", "serverIP" : "127.0.0.2" } ], "status" : false }` json.Unmarshal([]byte(str), &s) fmt.Println(s) //然后需要通过断言来将其从interface{}类型转成map[string]interface{}类型 m := s.(map[string]interface{}) for key, value := range m { switch v := value.(type){//得到s的类型 case string : fmt.Println(key , " is string ", v) case int : fmt.Println(key, "is int", v) case []interface{}: fmt.Println(key, "is an array") for i, vv := range v{ fmt.Println(i, vv) } default: fmt.Println(key, "is of a type i don't know how to handle") } } }

返回:

userdeMBP:go-learning user$ go run test.go
map[name:testJSON servers:[map[serverName:Shanghai_VPN serverIP:127.0.0.1] map[serverName:Beijing_VPN serverIP:127.0.0.2]] status:false] name is string testJSON servers is an array 0 map[serverName:Shanghai_VPN serverIP:127.0.0.1] 1 map[serverIP:127.0.0.2 serverName:Beijing_VPN] status is of a type i don't know how to handle

func 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函数会导致无休止的循环。

 

func MarshalIndent

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

MarshalIndent类似Marshal但会使用缩进将输出格式化。其可读性更高

 
举例:
package main 
import(
    "fmt"
    "encoding/json"
    "os"
)
type Address struct {
    City, State string
}
type Person struct {
    Id        int      `json:"id"` //id作为该JSON字段的key值
    FirstName string    //不设置标签则默认使用FirstName为字段key值
    LastName  string   `json:"-"` //字段被本包忽略,即使有值也不输出
    Age       int      `json:",omitempty"` //含omitempty选项的字段如果为空值会省略,如果存在Age作为该JSON字段的key值
    Height    float32  `json:"height,omitempty"` //含omitempty选项的字段如果为空值会省略,如果存在height作为该JSON字段的key值
    Address         //匿名字段(其标签无效)会被处理为其字段是外层结构体的字段,所以没有Address这个元素,而是直接显示City, State这两个元素
}

func main() {
    v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}
    v.Address = Address{"Hanga Roa", "Easter Island"}
    output, err := json.MarshalIndent(v, "&", "    ")//每行以&作为前缀,并缩进四个空格
    if err != nil {
        fmt.Printf("error: %v\n", err)
    }
    os.Stdout.Write(output)
}

返回:

userdeMBP:go-learning user$ go run test.go
{
&    "id": 13,
&    "FirstName": "John",
&    "Age": 42,
&    "City": "Hanga Roa",
&    "State": "Easter Island"
&}

如果使用的是Marshal,则返回:

userdeMBP:go-learning user$ go run test.go
{"id":13,"FirstName":"John","Age":42,"City":"Hanga Roa","State":"Easter Island"}

 未完待续

 
 

猜你喜欢

转载自www.cnblogs.com/wanghui-garcia/p/10431086.html