和其他语言中的函数相近,主要是将具有特定功能的一部分代码抽象成可复用的代码块
函数
函数定义
Go语言中定义函数使用func关键字,具体格式如下:
func 函数名(参数)(返回值){函数体}
函数调用
参数
类型简写
如果相邻变量的类型相同,则可以省略类型,如下:
func IntSum(x,y int) int {return x + y}
可变参数
可变参数一般是指函数的数量不固定
可变参数一般通过在参数名后面加...来标识
注意:一般可变参数通常要作为函数的最后一个参数
比如:
func intSum2(x ...int) int {fmt.Println(x) //x是一个切片sum := 0for _, v := range x {sum = sum + v}return sum}
返回值
多返回值
go语言中的函数支持多返回值,函数中如果有多个返回值,则必须使用()包裹起来
func calc(x, y int) (int, int) {sum := x + ysub := x - yreturn sum, sub}
返回值命名
函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return关键字返回。
func calc(x, y int) (sum, sub int) {sum = x + ysub = x - yreturn}
函数进阶
变量作用域
函数类型与变量
高阶函数
函数作为参数
有点类似于函数式编程
func add(x, y int) int {return x + y}func calc(x, y int, op func(int, int) int) int {return op(x, y)}func main() {ret2 := calc(10, 20, add)fmt.Println(ret2) //30}
函数作为返回值
func do(s string) (func(int, int) int, error) {switch s {case "+":return add, nilcase "-":return sub, nildefault:err := errors.New("无法识别的操作符")return nil, err}}
匿名函数与闭包
匿名函数
顾名思义,匿名函数就是在声明函数的时候并没有给函数一个名称
匿名函数的定义格式如下:
func(参数)(返回值){函数体}
闭包
闭包指的是一个函数和其相关的引用环境而组成的实体。简单来说,闭包=函数+饮用环境
func adder() func(int) int {var x intreturn func(y int) int {x += yreturn x}}func main() {var f = adder()fmt.Println(f(10)) //10fmt.Println(f(20)) //30fmt.Println(f(30)) //60f1 := adder()fmt.Println(f1(40)) //40fmt.Println(f1(50)) //90}
变量f是一个函数,并且引用了其外部作用域中的x变量,此时f就是一个闭包。
在f的生命周期内,变量x也一直有效,
闭包进阶实例1:
func adder2(x int) func(int) int {return func(y int) int {x += yreturn x}}func main() {var f = adder2(10)fmt.Println(f(10)) //20fmt.Println(f(20)) //40fmt.Println(f(30)) //70f1 := adder2(20)fmt.Println(f1(40)) //60fmt.Println(f1(50)) //110}
闭包进阶示例2:
func makeSuffixFunc(suffix string) func(string) string {return func(name string) string {if !strings.HasSuffix(name, suffix) {return name + suffix}return name}}func main() {jpgFunc := makeSuffixFunc(".jpg")txtFunc := makeSuffixFunc(".txt")fmt.Println(jpgFunc("test")) //test.jpgfmt.Println(txtFunc("test")) //test.txt}
defer语句
Go语言中的defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。
func main() {fmt.Println("start")defer fmt.Println(1)defer fmt.Println(2)defer fmt.Println(3)fmt.Println("end")}
上述代码的输出结果如下:
startend321
由于defer语句延迟调用的特性,所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。
defer语句的执行时机
在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:
defer经典案例
func f1() int {x := 5defer func() {x++}()return x}func f2() (x int) {defer func() {x++}()return 5}func f3() (y int) {x := 5defer func() {x++}()return x}func f4() (x int) {defer func(x int) {x++}(x)return 5}func main() {fmt.Println(f1())fmt.Println(f2())fmt.Println(f3())fmt.Println(f4())}
