Golang基础语法学习-3 | 青训营笔记

133 阅读2分钟

突然刷到一些go的关键字用法,自己完全不了解,在这个笔记里面做一个简单总结。

defer

  1. defer关键字用于注册延迟调用;
  2. 这些调用直到包含当前该defer关键字的函数执行完了才会被执行;
  3. 如果定义了多个defer语句,按照先进后出的方式执行,也即后定义的defer语句会先被执行,这也比较好理解,如果之前的资源释放掉了,后面需要使用掉之前资源的语句就没法执行了(可以用来逆序输出内容);
import (
	"fmt"
)
 
func f1() {
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
}
 
func main() {
	f1()
}

就比如上面这个输出就是:321,可以用于逆序输出是很值得记录的一个点。

但这个是多defer关键字注册延迟的情况,如果是:

package main  
  
import "fmt"  
  
type S struct{}  
  
func (s S) p(n int) S {  
fmt.Print(n)  
return s  
}

func main() {
var s S
defer s.p(1).p(2).p(3)
//fmt.Print(4)
}

那么这种方法链将让逆序输出无效,它的输出是:123

并且这种方法链其实只defer了最后一个方法即,s3.p(3)的执行,如果我们让main函数里面的打印恢复正常,那么会打印出来:1243,也就是说只有s3.p(3)会在main函数执行后执行。

func main() {
var s S
defer s.p(1).p(2).p(3)
fmt.Print(4)
}

4. defer语句中的变量,在defer声明的时候就决定了,也即在defer语句中使用到的变量的值为在defer语句之前的变量值(不包括匿名函数)

这里就不得不提“闭包”的使用带来的影响,因为defer语句中的值是根据该语句之前的变量最终值决定,所以如果放在一个循环里面,要打印出来循环对应的参量,那么循环defer只会打出来一个不变的最后的变量。

    package main
     
    import "fmt"
     
    func f1() {
    	a := []int{1, 4, 6, 2, 7}
    	for _, v := range a {
    		defer func() {
    			fmt.Println(v)
    		}()
    	}
    }
     
    func main() {
    	f1()
    }

defer语句主要有三个方面的用途:

  1. 关闭文件句柄;
  2. 锁资源释放;
  3. 数据库连接释放。