golang学习笔记(二)

golang学习笔记(二)

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的map
      m := 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方法释放写锁

欢迎找歪歪梯聊骚

原创文章 53 获赞 12 访问量 9132

猜你喜欢

转载自blog.csdn.net/weixin_44627989/article/details/105978530