golang学习笔记(二)
其他
2020-05-14 15:29:05
阅读次数: 0
Go异常处理
- error
go预先定义了一个error接口,包含一个字符串返回类型的函数,用于返回错误信息type error interface {
Error() string
}
可以同个errors包的new方法,传递一个字符串创建一个error对象err := errors.New("new Error")
- panic
panic语句用于抛出一个 error对象,其接收一个interface{}类型的参数,也就是任意类型。其可以接收一个字符串作为错误信息抛出,也可以接收一个error对象作为错误抛出,抛出后程序进入异常处理panic("error!!!")
//或者
panic(errors.New("error!!!"))
- defer
defer后的语句,会在当前调用defer语句的函数返回后执行,并且同个函数内部的defer语句是压栈执行(LIFO),最后的defer语句的内容将会在函数返回后立即执行,然后才执行倒数第二个defer语句内容,依次类推
defer类似java的finally语句,无论函数是抛出异常结束还是正常返回,都会在返回调用者前执行,比如func main(){
defer println("error occur")
panic("error")
println("finish")
}
最终输出error occur
panic: error
goroutine 1 [running]:
main.main()
d:/GoProject/errorDemo.go:5 +0x78
exit status 2
Process exiting with code: 1
- recover
recover函数只能在被defer修饰的内容(比如函数调用)中执行,其返回一个error对象(当程序抛出异常时)或者nil。当在defer中调用recover函数后,则异常不会再继续往外抛出,比如刚刚的代码修改为import "fmt"
func main() {
defer func() {
err := recover()
fmt.Printf("call recover get %v", err)
}()
panic("error")
println("finish")
}
最终输出call recover get error
因为异常出现,除了defer以外的语句都不会再执行,但是因为我们在defer中调用了recover所以异常不再对外抛出,不会像刚刚因为异常抛出到程序异常终止,但是main函数是正常结束了(panic后的语句不会执行),这时如果被结束的函数具备返回类型,则返回的都是0或者nil,即未初始化的默认值,比如import "fmt"
func test1() *int {
defer func() {
err := recover()
fmt.Printf("call recover get %v\n", err)
}()
panic("error")
a := 1
return &a
}
func test2() int {
defer func() {
err := recover()
fmt.Printf("call recover get %v\n", err)
}()
panic("error")
return 1
}
func main() {
a := test1()
b := test2()
println("a is ", a, " ,b is ", b)
}
最终输出call recover get error
call recover get error
a is 0x0 ,b is 0
new、make与管道
- new
new用于初始化一块内存空间并返回指针,用法为new(typeName)比如var p *int = new (int)
其实等价于var temp int
p := &temp
- make
- slice
make用于为slice(动态数组),map 或 chan (管道)初始化内存空间,并返回该对象(不是指针类型)。比如//创建一个长度为5的int slice
var a []int = make([]int ,5,10)
//与数组不同的是slice变量在赋值(函数传参等)时是引用赋值,而不是复制
其中第三个参数是capacity不指定默认等于slice初始长度,slice可以通过append方法扩容,当capacity足够时,扩容方法返回的还是当前slice的引用,如果capacity不够,则返回的是重新分配一块内存地址,复制旧元素,即返回的不是之前的地址,但是go会自动修改前面旧slice引用的地址为新地址,所以对旧slice使用不会有影响(旧变量也会引用到新地址)
- map
golang中定义一个map格式为var variable map[keyTypeName] valTypeName
比如通过make定义一个key为string,值为int的mapm := make(map[string] int)
m["key"] = 33
- 管道
golang中,chan类型代表管道,是一个线程安全的阻塞队列,如下定义一个接收int对象,缓冲容量为5的双向管道ch := make(chan int, 5)
其中第二个参数不指定默认为0,代表管道没有缓冲区,无缓冲管道的流入事件会阻塞到管道中产生流出事件,才流入,流入后直接流出
当管道具备缓冲区,如果管道中存储达到容量,则流入管道的操作回阻塞直到有容量,同理,当管道中内容为空时,流出管道操作回阻塞到管道中有数据
流入运算ch := make(chan int, 5)
ch<-5 //流入数值5
流出运算ch := make(chan int, 5)
<-ch //流出一个数值
ch<-9 //流入一个9
a := <-ch //流出数值赋值给变量
同时还可以指定管道为只读或者只写管道,如onlyReadChan := make(<-chan int)
onlyWriteChan := make(chan<-int)
Go多线程
- go关键字
golang中提供go关键字来开启一个goroutine(go中的协程,类似线程,但是一个线程下可以有多个协程),用法为go 函数调用
比如如下代码,开启一个goroutine去执行println(“a”)go println("a")
比较特殊的情况是,如果程序的main函数结束了,则所有goroutine会被终止
- runtime包
go的runtime包中提供了多线程的一些库函数
- Gosched 使得当前goroutine放弃当前的cpu时间片,进入竞争cpu资源状态
- NumCPU 返回当前系统的cpu核数
- GOMAXPROCS 设置当前go程序最大使用的cpu核数
- Goexit 终止当前的goroutine(defer语句会执行)
- NumGoroutine 返回当前处于等待执行和正在执行状态的goroutine数量
- GOOS 设置当前程序的目标操作系统,通过修改该参数,使得go build出不同的二进制代码
- time包
go的time包中提供了一些时间处理和线程休眠、定时的函数
- Sleep 休眠当前的goroutine
- Tick 返回一个定时新增数据的chan
- sync包
go的sync包提供了锁控制的一些库函数
- Mutex 互斥锁,其Lock方法阻塞获得锁,unlock方法释放锁
- RWMutex 读写锁,RLock方法使用读锁,Lock方法使用写锁,RUnLock方法释放读锁,UnLock方法释放写锁
转载自blog.csdn.net/weixin_44627989/article/details/105978530