Go学习笔记

理解指针

指针类型和普通类型区别
package main

import (
	"fmt"
)

type User struct {
	Id   int64
	Name string
}

func (user *User) getUserInfo() string {
	return fmt.Sprintf("%d %s", user.Id, user.Name)
}

func main() {
	n1 := 10
	n2 := 20
	setValue(n1, &n2)
	fmt.Println("n1:", n1, "n2:", n2)

	// u1是个对象
	u1 := User{
		Id:   10,
		Name: "tom",
	}
	println(u1.getUserInfo())

	// u2是个指针
	u2 := new(User)
	u2.Id = 20
	u2.Name = "jerry"
	println(u2.getUserInfo())

	// u3是个指针
	u3 := &User{
		Id:   30,
		Name: "tonny",
	}
	println(u3.getUserInfo())

	println("u1 地址", &u1)
	println("u2 指针", u2)
	setStruct(u1, u2)

	println("---------")
	println(u1.getUserInfo())
	println(u2.getUserInfo())
	println(u3.getUserInfo())

}

func setValue(n1 int, n2 *int) {
	n1 += 1
	*n2 += 1
}

// user01 传的是对象,相当于把赋值给了这个对象,这个对象和原对象地址不是同一个,任何修改不会影响原对象
// user02 传的是地址,任何修改都会修改原对象
func setStruct(user01 User, user02 *User) {
	//user01.Name = "修改user01"
	//user02.Name = "修改user02"

	println("setStruct user01 地址", &user01)
	println("setStruct user02 指针", user02)

	updateName(&user01.Name)
	updateName(&user02.Name)
}

func updateName(name *string) {
	*name = "更新name"
}
指针类型和普通类型初始化
package main

import (
	"fmt"
)

type OtherInfo struct {
	info  *string
	info2 string
}

func (otherInfo *OtherInfo) getOtherInfoStr() string {
	fmt.Println("执行getOtherInfoStr")
	return fmt.Sprint(otherInfo.info, otherInfo.info2)
}

type User struct {
	name       *string    // 指针类型,默认是nil
	name2      string     // 普通类型,默认是""
	otherInfo  *OtherInfo // 指针对象,默认nil
	otherInfo2 OtherInfo  // 普通对象,默认{},相当于new好了一个对象
}

func main() {

	user := new(User)
	printUser(*user)

	str := "名字"
	user.name = &str
	user.name2 = "名字2"

	user.otherInfo = &OtherInfo{info2: "信息"}
	user.otherInfo2.info2 = "信息2"

	printUser(*user)

}

func printUser(user User) {
	fmt.Println("=================")
	fmt.Println("user:", user)
	fmt.Println("user.name:", user.name)
	fmt.Println("user.name2:", user.name2)
	fmt.Println("user.otherInfo:", user.otherInfo)
	if user.otherInfo != nil {
		fmt.Println("user.otherInfo.info:", user.otherInfo.info)
		fmt.Println("user.otherInfo.getOtherInfoStr():", user.otherInfo.getOtherInfoStr())
	}
	fmt.Println("user.otherInfo2:", user.otherInfo2)
	fmt.Println("user.otherInfo2.info:", user.otherInfo2.info)
	fmt.Println("user.otherInfo2.getOtherInfoStr():", user.otherInfo2.getOtherInfoStr())
}

 

认识defer、recover、panic关键字

查看代码
 package main

import (
	"fmt"
)

func main() {
	// deferTest()

	/**
	总结
	1、defer延迟执行异常处理
	2、recover会捕获抛出的异常(主动异常或未知异常)
	3、panic会主动抛出异常
	*/
	defer exceptionCatch()
	panicTest(true)

}

// panic英⽂意思是恐慌,在这⾥意思是抛出⼀个程序异常,即报告程序运⾏时错误
func panicTest(throw bool) {
	println("panicTest begin")

	if throw {
		panic("抛出一个异常")
	}
	println("panicTest end")

}

// defer有延迟的意思,就是稍后执⾏,先执⾏函数主体内容,defer的内容稍后执⾏
func deferTest() {
	// 异常处理 内置函数方式
	//defer func() {
	//	if r := recover(); r != nil {
	//		fmt.Println("Some error happened!", r)
	//		ret = -1
	//	}
	//}()

	// 异常处理 外部函数方式
	defer exceptionCatch()

	array := [3]int{2, 3, 4}
	index := 0
	for ; index < 10; index++ {
		println(array[index])
	}
}

// recover() 函数⽤于终⽌错误处理流程,也就是我们常规说的 catch
func exceptionCatch() {
	if r := recover(); r != nil {
		fmt.Println("出现异常了:", r)
	}
}

 

等待所有协程执行完

查看代码
 package main

import (
	"fmt"
	"sync"
	"time"
)

// var waitGroup = sync.WaitGroup{} // 这种是主动申请了一个对象
var waitGroup sync.WaitGroup // 这种是默认赋值了一个对象,结果一样
var waitGroup2 sync.WaitGroup

func main() {
	run01()
	run02()
	fmt.Println("主协程执行结束")

}

func run01() {
	waitGroup.Add(2)

	go func() {
		time.Sleep(time.Second)
		fmt.Println("执行协程A")
		waitGroup.Done()
	}()

	go func() {
		time.Sleep(time.Second)
		fmt.Println("执行协程B")
		waitGroup.Done()
	}()

	// 等待所有协程执行完毕
	waitGroup.Wait()
}

func run02() {
	waitGroup2.Add(1)

	go func() {
		time.Sleep(time.Second)
		fmt.Println("执行协程C")
		waitGroup2.Done()
	}()

	// 等待所有协程执行完毕
	waitGroup2.Wait()
}

 

加锁、释放锁

查看代码
 package main

import (
	"fmt"
	"sync"
	"time"
)

var count = 10
var waitGroup sync.WaitGroup
var mutex sync.Mutex

func main() {

	waitGroup.Add(2)
	go run("协程A")
	go run("协程B")

	waitGroup.Wait()

	fmt.Println("主协程执行完成")
}

func run(name string) {
	defer waitGroup.Done()
	for {
		mutex.Lock() // 加锁
		if count <= 0 {
			mutex.Unlock() // 释放锁
			break
		} else {
			time.Sleep(time.Second)
			count--
			mutex.Unlock() // 释放锁
		}
		fmt.Println(name, "count: ", count)
	}
}

 

读写锁使用

查看代码
 package main

import (
	"fmt"
	"sync"
	"time"
)

var waitGroup *sync.WaitGroup
var rwMutex *sync.RWMutex

func init() {
	// 两种指针对象化方式
	waitGroup = &sync.WaitGroup{}
	rwMutex = new(sync.RWMutex)
}

func main() {

	waitGroup.Add(4)

	go read("协程A")
	go read("协程B")

	go write("协程C")
	go write("协程D")

	waitGroup.Wait()
	fmt.Println("主协程执行完成")
}

// 读-读 之间不互斥
func read(name string) {
	defer waitGroup.Done()

	fmt.Println(name, "开始读数据,准备加锁")
	rwMutex.RLock() // 读锁

	fmt.Println(name, "读数据 begin")
	time.Sleep(time.Second)
	fmt.Println(name, "读数据 end")

	rwMutex.RUnlock() // 释放读锁
	fmt.Println(name, "读数据结束,释放锁")
}

// 读-写 写-写 之间互斥
func write(name string) {
	defer waitGroup.Done()

	fmt.Println(name, "开始写数据中,准备加锁")
	rwMutex.Lock()

	fmt.Println(name, "写数据 begin")
	time.Sleep(time.Second)
	fmt.Println(name, "写数据 end")

	rwMutex.Unlock()
	fmt.Println(name, "写数据结束,释放锁")
}
posted on 2023-04-12 11:33  wzyy  阅读(35)  评论(0编辑  收藏  举报