前言
这是我参与「第五届青训营 」伴学笔记创作活动的第 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 main
import (
"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,因为仅作为示范,所以需要手动添加转义字符。
写在最后
本文是我的日常学习笔记,如果哪里有写错,麻烦请指出来,感谢。这里我也推荐大家多写笔记,写笔记是一个很好的习惯,可以帮助我们更好的吸收和理解学习的新知识,新的一年大家一起加油!