Go语言中的defer
语句会将其后面跟随的语句进行延迟处理。在defer
归属的函数即将返回时,将延迟处理的语句按defer
定义的逆序进行执行,也就是说,先被defer
的语句最后执行,最后被defer
的语句,最早被执行。git
func main() { fmt.Println("start") defer fmt.Print(1) defer fmt.Print(2) defer fmt.Print(3) fmt.Println("end") } // 结果:start end 3 2 1
因为defer
语句延迟调用的特性,因此defer
语句能很是方便的处理资源释放问题。。好比:资源清理、文件关闭、解锁及记录时间等。github
在Go语言的函数中return
语句在底层并非院子操做,它分为给返回值赋值和RET指令两步。而defer
语句执行的实际就在返回值赋值操做后,RET指令执行前。具体以下图所示:
函数
func f1() int { x := 5 defer func() { x++ }() return x } func f2() (x int) { defer func() { x++ }() return 5 } func f3() (y int) { x := 5 defer func() { x++ }() return x } func f4() (x int) { defer func(x int) { x++ }(x) return 5 } func main() { fmt.Println(f1()) // 5 fmt.Println(f2()) // 6(x等于5,返回值等于x,因此x++后返回值会改变) fmt.Println(f3()) // 5 fmt.Println(f4()) // 5 }
包(package)
是多个Go源码的集合,是一种高级的代码复用方案,Go语言为咱们提供了不少内置包,如fmt
、os
,io
等。code
咱们还能够根据本身的须要建立本身的包。一个包能够简单理解为一个存放.go
文件的文件夹。该文件夹下面的全部go文件都要在代码的第一行添加以下代码,声明该文件归属的包。blog
package 包名
注意事项资源
-
符号。若是想在一个包中引用另一个包里的标识符(如变量、常量、类型、函数等)时,该标识符必须是对外可见的。在Go语言中只须要将标识符的首字母大写就可让标识符对外可见了。编译器
package main import "fmt" var a = 100 // 首字母小写,外部包不可见,只能在当前包内使用 // 首字母大写外部包可见,可在其余包中使用 const Mode = 1 type person struct { // 首字母小写,外部包不可见,只能在当前包内使用 name string }
要在代码中引用其余包的内容,须要使用import
关键字导入使用的包。具体语法以下:源码
import "包的路径"
** 注意事项string
$GOPATH/src/
后开始计算的,使用/
进行路径分隔。单行导入的格式以下:it
import "包1" import "包2"
import (
"包1"
"包2"
)
在导入包名的时候,咱们还能够为导入的包设置别名。具体语法格式以下:
import 别名 "包的路径"
单行导入方式定义别名:
import "fmt" import m "github.com/aaa/bbb/ccc"
多行导入方式定义别名:
import ( "fmt" m "github.com/aaa/bbb/ccc" )
若是只但愿导入包,而不使用包内部的数据时,可使用匿名导入包。具体的格式以下:
import _ "包的路径"
在Go语言程序执行时导入包语句会自动触发包内部init()
函数的调用。须要注意的是:init()
函数没有参数也没有返回值。init()
函数在程序运行时自动被调用执行,不能在代码中主动调用它。
包初始化执行的顺序以下图所示:
Go语言包会从main
包开始检查其导入的全部包,每一个包中又可能导入了其余的包。Go编译器由此构建出一个树状的包引用关系,再根据引用顺序决定编译顺序,依次编译这些包的代码。
在运行时,被最后导入的包会最早初始化并调用其init()
函数,以下图所示: