Json

Json 的基本类型有:

  1. 布尔类型,例如 true 和 false
  2. 数字,例如 1.23
  3. 字符串,例如"张三"
  4. 数组,例如 ["go","PHP"],每个元素之间用逗号隔开
  5. 对象,如下所示,每个元素之间用逗号隔开
{
    "year":1980,
  "name":"张三"
}

其中,go 和 json 的数据结构体对应关系如下所示。

bool,                   for JSON booleans  
float64,                for JSON numbers 
int,                    for JSON 整数
string,                 for JSON strings
nil,                    for JSON null

// 这个都是接口类型,在获取值的是比较麻烦
[]interface{},          for JSON arrays  
map[string]interface{}, for JSON objects // 因为json的对象里的值有各种类型,所以值要接口类型

// 例如,对于数组
[]int  for  [1,2,3]
[]string for ["red","green"]
[]struct{Title string} for [{"Title":"功夫足球"},{"Title":"功夫"}]

// 例如对于对象,通常用结构体会比较好,不同的字段类型和不同的json数据结构对应上
struct{
    Title string
    Release int
} for {"Title":"功夫足球","Release":2004}

// 但是对应动态key的json,还是得用map,以下的年份作为动态key
map[string]struct{Title string} for {
   "2000":{"Title":"功夫足球"},
  "2004":{"Title":"功夫"},
}

编码

Go 中使用 marshal ,把结构体转为 json,如下所示:

type Movie struct {
  Title  string
   Year   int  `json:"released"`
 Color  bool `json:"color,omitempty"`
  Actors []string
}

func main() {
   var movies = []Movie{
       {
           Title:  "功夫足球",
           Year:   2001,
           Color:  true,
           Actors: []string{"周星驰"},
      },
      {
           Title:  "功夫",
         Year:   2004,
           Color:  false,
          Actors: []string{"周星驰"},
      },
  }

   // data, err := json.Marshal(movies)
    data, err := json.MarshalIndent(movies, "", "    ")// 可缩进格式化输出json
  if err != nil {
     log.Fatalf("Json Marshal failed:%s", err)
 }
   fmt.Printf("%s", data)
}

将得到如下结果,其中有几个需要注意的是:

  1. 默认是将结构体成员的名称作为 json 对象里的字段的名称
  2. 只有可导出的成员变量才会被转为 json 字段,所以结构体的字段都要大写开头
  3. 在字段后面可以指定成员标签,成员标签可以是任意字符串,但是按照习惯,是由一串由空格分开的键值对 key:"value" 组成。例如 json:"released",指定结构体成员对应 Json 字段的名字
  4. Color 成员标签有另外一个参数 omitempty,它表示这个成员的值是其零值或者为空,则不输出这个成员到 Json 中。
[
    {
        "Title": "功夫足球",
        "released": 2001,
        "color": true,
        "Actors": [
            "周星驰"
        ]
    },
    {
        "Title": "功夫",
        "released": 2004,
        "Actors": [
            "周星驰"
        ]
    }
]

解码

Go 中使用 unmarshal 来将 json 字符串解码为 go 数据结构。通过合理的定义 Go 的数据结构,我们可以选择哪部分 json 数据解码到结构体对象中,哪些数据可以丢弃。例如下例中,我们只需要解码 title 字段。

jsonStr := `[{"Title":"功夫足球","released":2001,"color":true,"Actors":["周星驰"]},{"Title":"功夫","released":2004,"Actors":["周星驰"]}]`
var titles []struct{ Title string }
// 此时title还是nil,函数会先申请一个值并使指针指向它
if err := json.Unmarshal([]byte(jsonStr), &titles); err != nil {
 log.Fatalf("Json 反序列化失败:%s", err)
}
fmt.Println(titles)

需要注意的是:

  1. 结构体的成员的名称的首字母必须大写
  2. Json 字符串的字段名称并不需要大写开头,关联到结构体字段的时候,是忽略大小写的
  3. 只有在 json 字段中有下划线,go 里没有下划线的时候,才需要使用成员标签定义
  4. json 中有的字段,结构体中可以没有,结构体中有的字段,json 中可以没有,但是一旦字段匹配上,字段的类型一定要一致,不然会异常

解码除了使用 unmarshal 。还可以使用 NewDecoder 进行解析

json.NewDecoder 是从一个流里面直接进行解码,代码精干,可以从 http 连接与 socket 连接的读取与写入,或者也可以从文件读取,速度比较快

result := new(map[string]interface{})
var json_str = `{"bool":true,"str":"你好"}` // 可以是 http 连接的流
resultType := reflect.TypeOf(result)
if resultType.Kind() != reflect.Ptr {
  fmt.Println("result 对象必须是指针!")
    return
}
decode := json.NewDecoder(bytes.NewBufferString(json_str))
// 防止 int64 丢失精度
decode.UseNumber()
if err := decode.Decode(result); err != nil {
    fmt.Println("解析失败!")
  return
}
fmt.Println(result)
最后修改:2023 年 12 月 30 日
如果觉得我的文章对你有用,请随意赞赏