20.2 JSON-JSON解码、映射数据类型、处理JSON响应

1. JSON解码

JSON解码,即将JSON格式在字符串转换为Go语言数据类型的变量。

函数Unmarshal接受一个JSON字节切片和一个指定目标格式的接口。而这个借口即与JSON字符串中的结果相匹配的结构体类型的变量

  • 定义结构体类型
    • type Person struct { ... }
  • 创建结构体变量
    • p := Person{}
  • 将JSON格式的字符串转换JSON格式的字节切片
    • jb := []byte(js) 
  • 将JSON格式的字节切片解码为结构体变量
    • err := json.Unmarshal(jb, &p)

// 将JSON字符解码为结构体
//             []byte               json.Unmarshal 
// JSON字符串 ------> JSON字节切片 --------------> 结构体
package main

import (
    "encoding/json"
    "fmt"
    "log"
)

// Person with name, age and hobbies
type Person struct {
    Name    string
    Age     int 
    Hobbies []string
}

func main() {
    js := `{"Name":"George","Age":40,"Hobbies":["Cycling","Cheese","Techno"]}`
    fmt.Println(js)
	
	jb := []byte(js)	// 将json字符串转化为字节切片
    p := Person{}	// json目标对象接口
    
	err := json.Unmarshal(jb, &p)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%+v\n", p)
}
// 打印输出:
{"Name":"George","Age":40,"Hobbies":["Cycling","Cheese","Techno"]}
{Name:George Age:40 Hobbies:[Cycling Cheese Techno]} 

默认情况下,JSON字符串中的分别映射结构体中的字段名字段值(大小写敏感)。

  • {"Name":"George","Age":40,"Hobbies":["Cycling","Cheese","Techno"]}
  • type Person struct {
  •     Name    string
  •     Age     int
  •     Hobbies []string
  • }

如果为结构体字段指定了JSON标签,则以标签文本对应JSON字符串的键。

  • {"name":"George","age":40,"hobbies":["Cycling","Cheese","Techno"]}
  • type Person struct {
  •     Name    string   `json:"name"`
  •     Age     int      `json:"age"`
  •     Hobbies []string `json:"hobbies"`
  • }
// 映射JSON键到结构体字段
// 默认情况下,JSON字符串中的键和值分别映射结构体中的字段名和字段值,但
// 如果为结构体中的字段指定了JSON标签,则以标签文本对应JSON字符串的键
// 
// type 结构体 struct {
//     字段1 类型1 `json:"键1"` 
//     字段2 类型2 `json:"键2"` 
//     ... 
//     字段n 类型n `json:"键n"`
// }
package main

import (
   "encoding/json"
   "fmt"
   "log"
   "testing"
)
// Person with name, age and hobbies
type Person4 struct {
   Name    string   `json:"MyName"`
   Age     int      `json:"MyAge"`
   Hobbies []string `json:"MyHobbies"`
}

func TestJson2Struct2(t *testing.T) {
   js := `{"MyName":"George","MyAge":40,"MyHobbies":["Cycling","Cheese","Techno"]}`
   fmt.Println(js)
   jb := []byte(js)
   p := Person4{}
   err := json.Unmarshal(jb, &p)
   if err != nil {
      log.Fatal(err)
   }

   fmt.Printf("%+v\n", p)
}
// 打印输出:
{"name":"George","age":40,"hobbies":["Cycling","Cheese","Techno"]}
{Name:George Age:40 Hobbies:[Cycling Cheese Techno]}

 2. 映射数据类型

Go是一种强类型语言,而JavaScript是一种弱类型语言encoding/json包根据以下所列规则,在两种语言的类型系统之间进行显式类型转换。

JSON

Go

Boolean

bool

Number

float64

String

string

Array

[]interface{}(切片类型)

Object

map[string]interface{}

(映射类型)

Null

nil

js := `{

    "Boolean" : false,

    "Number"  : 4,

    "String"  : "Helo World!",

    "Array"   : [1, 2, 3, 4, 5],

    "Object"  : {"MON": 1, "TUE": 2, "WED": 3, "THU": 4, "FRI": 5},

    "Null"    : null

    }`

type Types struct {

    Boolean bool

    Number  float64

    String  string

    Array   []int

    Object  map[string]int

    Null    *int

   }

// JSON的数据类型
// JSON的数据类型与Go的数据类型存在如下对应关系: 
//
// +--------------+------------------------+
// |     JSON     |           Go           |
// +--------------+------------------------+
// | Boolean      | bool                   |
// | Number       | float64                |
// | String       | string                 |
// | Array        | []interface{}          |
// | Object       | map[string]interface{} |
// | Null         | nil                    |
// +--------------+------------------------+
package main

import (
    "encoding/json"
    "fmt"
    "log"
)
// Types of JSON data
type Types struct {
    Boolean bool 
    Number  float64
    String  string 
    Array   []int 
    Object  map[string]int 
    Null    *int 
} 

func main() {
    js := `{
    "Boolean" : false,
    "Number"  : 4,
    "String"  : "Helo World!",
    "Array"   : [1, 2, 3, 4, 5],
    "Object"  : {"MON": 1, "TUE": 2, "WED": 3, "THU": 4, "FRI": 5},
    "Null"    : null
}`
    fmt.Println(js)

    jb := []byte(js)
    t := Types{}
    err := json.Unmarshal(jb, &t)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%+v\n", t)
} 
// 打印输出:
{
    "Boolean" : false,
    "Number"  : 4,
    "String"  : "Helo World!",
    "Array"   : [1, 2, 3, 4, 5],
    "Object"  : {"MON": 1, "TUE": 2, "WED": 3, "THU": 4, "FRI": 5},
    "Null"    : null
}
{Boolean:false Number:4 String:Helo World! Array:[1 2 3 4 5] Object:map[MON:1 TUE:2 WED:3 THU:4 FRI:5] Null:<nil>}

 3. 处理JSON响应

在Go语言中,通过标准库net/http包的Get函数获取到的HTTP响应是一个输入流(实现了io.Reader接口),而非字符串或字节切片。其中JSON格式的数据无法直接通过encoding/json包的Unmarshal函数解码为结构体变量,需先转化为字节切片。

调用encoding/json包的NewDecoder函数可以创建一个JSON解码器。该解码器将其被创建时传入的输入流作为数据源,并通过Decode方法将数据源中的JSON数据解码为结构体变量,借助该方法的参数输出给调用者。

  • type User struct { ... }
  • response, err := http.Get("https://api.github.com/users/shapeshed")
  • decoder, user := json.NewDecoder(response.Body), User{}返回解码器对象decoder,解码器具备了对json格式响应的读取能力;
  • err = decoder.Decode(&user) // 解码并填写user结构体的字段
// 解析JSON格式的API返回值
// 响应 = http.Get(API的URL)
// 解码器 = json.NewDecoder(响应体)
// 解码器.Decode(&结构体)
package main
import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
)
// User of Github 
type User struct {
    Name string `json:"name"`
    Blog string `json:"blog"`
}

func main() {    
    response, err := http.Get( // 获取response
        "https://api.github.com/users/shapeshed")
    if err != nil {
        log.Fatal(err)
    }

    defer response.Body.Close()
    decoder, user := json.NewDecoder(response.Body), User{}

    err = decoder.Decode(&user)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%+v\n", user)
}
// 打印输出:
{Name:George Ornbo Blog:http://shapeshed.com}

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值