GO语言基础入门-JSON序列化和反序列操作 | 青训营笔记

234 阅读6分钟

前言

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天,其实第五届青训营已经正式开课n多天了,笔记不断更新中,都是我听完课之后的总结和平时自己的学习积累,分享出来给有需要的朋友。

本文内容

本文将涉及到Go语言Json序列化和反序列化相关操作,GO协程、线程和进程的基本概念,协程的基本使用。

Go语言基础

1.GO语言json序列化
(1)对结构体进行json序列化
package main
​
import (
    "encoding/json"
    "fmt"
)
​
​
type Monster struct {
    //对于结构体的序列化,如果我们希望序列化后key的名字,由我们重新制定,那么可以给struct指定一个tag标签
    Name     string `json:"name"` //使用tag将大写Name改为name,运用反射机制
    Age      int
    Birthday string
    Sal      float64
    Skill    string
}
​
// 演示对结构体进行json序列化
func testStruct() {
    //演示
    monster := Monster{
        Name:     "孙悟空",
        Age:      500,
        Birthday: "1200-11-06",
        Sal:      10000,
        Skill:    "火眼金睛",
    }
    //将monster序列化
    data, err := json.Marshal(&monster)
    if err != nil {
        fmt.Println("序列化错误", err)
    }
    //序列化后的结果
    fmt.Println("monster序列化后的结果为", string(data))
​
}
(2)将map进行序列化
func testMap() {
    //定义一个map
    var a map[string]interface{}
    //使用map,需要make
    a = make(map[string]interface{})
    a["name"] = "红孩儿"
    a["age"] = 25
    a["address"] = [2]string{"东海龙宫", "火焰山"}
​
    //将a序列化
    data, err := json.Marshal(a) //因为map本身是引用传递,所以不用加&
    if err != nil {
        fmt.Println("序列化错误", err)
    }
    //序列化后的结果
    fmt.Println("map序列化后的结果为", string(data))
}
(3)对切片进行序列化
// 演示对切片进行序列化,我们这个切片[]map[string]interface{}
func testSlice() {
    var slice []map[string]interface{}
    var m1 map[string]interface{}
    //使用map前,需要先make
    m1 = make(map[string]interface{})
    m1["name"] = "康康"
    m1["age"] = "7"
    m1["address"] = "北京"
    slice = append(slice, m1)
    var m2 map[string]interface{}
    m2 = make(map[string]interface{})
    m2["name"] = "Mike"
    m2["age"] = "10"
    m2["address"] = "美国"
    slice = append(slice, m2)
​
    //将monster序列化
    data, err := json.Marshal(slice)
    if err != nil {
        fmt.Println("序列化错误", err)
    }
    //序列化后的结果
    fmt.Println("切片序列化后的结果为", string(data))
}

运行结果:

10,true

需要注意如果不接收第二个参数也就是上面代码中的 ok,断言失败时会直接造成一个 panic。如果 x 为 nil 同样也会 panic。

示例2:

package main
​
import (
    "fmt"
)
​
type Student struct {
}
​
// 编写一个函数,可以判断输入的参数是什么类型
func TypeJudge(items ...interface{}) {
    for index, x := range items {
        switch x.(type) {
        case bool:
            fmt.Printf("第%v个参数是bool类型,值是%v\n", index+1, x)
        case int, int32, int64:
            fmt.Printf("第%v个参数是int类型,值是%v\n", index+1, x)
        case float32:
            fmt.Printf("第%v个参数是float32类型,值是%v\n", index+1, x)
        case float64:
            fmt.Printf("第%v个参数是float64类型,值是%v\n", index+1, x)
        case string:
            fmt.Printf("第%v个参数是string类型,值是%v\n", index+1, x)
        case Student: //类型断言
            fmt.Printf("第%v个参数是Student类型,值是%v\n", index+1, x)
        case *Student: //类型断言
            fmt.Printf("第%v个参数是*Student类型,值是%v\n", index+1, x)
        default:
            fmt.Printf("第%v个参数类型不确定,值是%v\n", index+1, x)
        }
    }
}
​
func main() {
    var n1 float32 = 1.1
    var n2 float64 = 2.2
    var n3 int32 = 50
    var n4 string = "小王"
    address := "福建"
    n5 := true
    var stu Student = Student{}
    var stu2 *Student = &Student{}
    TypeJudge(n1, n2, n3, n4, address, n5, stu, stu2)
}
2.GO语言json反序列化

将json反序列化为原来的数据类型,在反序列化一个json字符串时,要确保反序列化后的数据类型和原来序列化的数据类型。

(1)字符串反序列化为struct结构体
// 演示将json字符串,反序列化为struct结构体
type Monster struct {
    Name     string
    Age      int
    Birthday string
    Sal      float64
    Skill    string
}
​
func unMarshalStruct() {
​
    json_str := "{"name":"孙悟空","Age":500,"Birthday":"1200-11-06","Sal":10000,"Skill":"火眼金睛"}"
    //定义一个Monster实例
    var monster Monster
​
    err := json.Unmarshal([]byte(json_str), &monster)
    if err != nil {
        fmt.Println("unmarshal err:", err)
    }
    fmt.Println("反序列化struct后:", monster, monster.Name)
​
}
​
(2)字符串反序列化为map
// 演示将json字符串,反序列化为map
func unMarshalMap() {
    json_str := "{"address":["东海龙宫","火焰山"],"age":25,"name":"红孩儿"}" //map
    //定义一个map
    // 注意:反序列化map,不需要make,因为make操作被封装到Unmarshal函数了
    var a map[string]interface{}
    err := json.Unmarshal([]byte(json_str), &a)
    if err != nil {
        fmt.Println("unmarshal err:", err)
    }
    fmt.Println("反序列化map后:", a, a["name"])
}

因为writer是带缓存,因此在调用WriterString方法时,其实内容是先写入到缓存的,所以需要调用Flush方法,将带缓冲的数据真正写入到文件中。

(3)json字符串反序列化为切片
// 演示将json字符串,反序列化为切片
func unMarshalSlice() {
    json_str := "[{"address":"北京","age":"7","name":"康康"},{"address":"美国","age":"10","name":"Mike"}]" //切片
    fmt.Println(json_str)
    //定义一个切片
    // 注意:反序列化切片,不需要make,因为make操作被封装到Unmarshal函数了
    var slice []map[string]interface{}
    err := json.Unmarshal([]byte(json_str), &slice)
    if err != nil {
        fmt.Println("unmarshal err:", err)
    }
    fmt.Println("反序列化slice后:", slice, slice[0]["name"])
​
}
3.GO语言协程goroutine
(1)goroutine 协程相关概念

1.进程和线程的概念

(1)进程就是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位

(2)线程就是进程的一个执行实例,是程序执行的最小单元,它是比进程更小的能独立运行的基本单位

(3)一个进程可以创建和销毁多个线程,同一个进程中的多线程可以并发执行

(4)一个程序运行至少有一个进程,一个进程至少有一个线程

2.并发和并行的概念

(1)并发是指多线程程序单核在cpu上运行(微观上实际同一时间点只运行了一个线程)

(2)并行是指多线程程序在多核cpu上运行

3.协程概念

(1)主线程是一个物理线程,直接作用在cpu上的,是重量级的,非常耗费cpu资源。

(2)协程是从主线程开启的,是轻量级的线程,是逻辑态。对资源消耗相对较小

4.MPG模式基本介绍

(1) M:操作系统的主线程(是物理线程)

(2) P:协程执行需要的上下文

(3) G:协程

(2)goroutine 实例
package mainimport (
    "fmt"
    "strconv"
    "time"
)
// 编写一个函数,每隔1秒输出“hello,world”
func test() {
    for i := 1; i <= 10; i++ {
        fmt.Println("test() hello,world" + strconv.Itoa(i))
        time.Sleep(time.Second)
    }
}
​
func main() {
    go test() //使用go 开启了一个协程
    //开启协程后 交叉运行,不会阻塞
    for i := 1; i <= 10; i++ {
        fmt.Println("main() hello ,golang" + strconv.Itoa(i))
        time.Sleep(time.Second)
    }
    //注意:这里当主线程执行结束后,无论协程是否执行结束,都将停止运行(主线程不会等待)
}

总结

1、在反序列化一个json字符串时,要确保反序列化后的数据类型和原来序列化前的数据类型一致。

2、JSON字符串如果是通过程序得到的话,那么字符串中的""不需要转义处理。我们自行定义str,因为仅作为示范,所以需要手动添加转义字符。

写在最后

本文是我的日常学习笔记,如果哪里有写错,麻烦请指出来,感谢。这里我也推荐大家多写笔记,写笔记是一个很好的习惯,可以帮助我们更好的吸收和理解学习的新知识,新的一年大家一起加油!