go:函数
1. 简介
1.1 函数类型
1. 普通带有名字的函数;
2. 匿名函数或者 lambda 函数;
3. 方法(Methods)
1.2 函数签名
除了main()、init()函数外,其它所有类型的函数都可以有参数与返回值。函数参数、返回值以及它们的类型被统称为函数签名;
go里面函数不允许重载,函数名需保证在包内的唯一性;
1.3 函数作为参数
函数可以将其他函数作为它的参数,只要这个被调用函数的返回值个数、返回值类型和返回值的顺序与调用函数所需求的实参是一致的;
示例:
package main import "fmt" func main() { fun1(fun2()) } func fun1(a int,b int,c int) { fmt.Println(a,b,c) } func fun2()(a int,b int,c int) { return 1,2,3 }
1.4 函数类型
函数也可以以申明的方式被使用,作为一个函数类型;
函数类型可以赋值给变量,就像 add := binOp
一样,这个变量知道自己指向的函数的签名,所以给它赋一个具有不同签名的函数值是不可能的;
函数值(functions value)之间可以相互比较:如果它们引用的是相同的函数或者都是 nil 的话,则认为它们是相同的函数;
type binOp func(int, int) int
1.5 声明外部定义的函数
如果需要申明一个在外部定义的函数,你只需要给出函数名与函数签名,不需要给出函数体:
func flushICache(begin, end uintptr) // implemented externally
2. 函数参数和返回值
go 语言的函数可以返回多个返回值,称为一组返回值;
函数定义时,它的形参一般是有名字的,不过我们也可以定义没有形参名的函数,只有相应的形参类型,就像这样:func add ( int, int )
没有参数的函数通常被称为 niladic 函数(niladic function),就像 main.main()
2.1 值传递和引用传递
函数调用时默认采用值传递的方式传递参数,传递的都是变量的副本,函数中对参数副本的修改不影响参数的值;
如果需要函数直接修改参数的值,可以传递参数的地址(即指针),这样函数就可以直接修改参数的值,传递参数地址的形式:&varName;
传递指针赋予了函数改变外部变量的能力,还可以节省内存,被修改的变量也不用return
传递参数地址的本质也是值传递,指针也是变量类型,有自己的地址和值,通常指针的值指向一个变量的地址。所以,按引用传递也是按值传递;
2.2 返回值命名
尽量使用命名返回值:会使代码更清晰、更简短,同时更加容易读懂。
返回值只有数据类型,没有命名返回参数名称的时候,直接返回对应类型的值即可;
func func3()(int,int) { return 2,3 }
返回值命名了参数名称时,在对返回参数赋值后,直接return即可,不用显示return 返回参数,如果没有对返回参数进行赋值操作,则返回该参数类型的零值;
func main() { i, i2 := func3() fmt.Println(i,i2) a1, a2 := func4() fmt.Println(a1,a2) a12, a22 := func5() fmt.Println(a12,a22) } func func3()(int,int) { /** 输出:2 3 */ return 2,3 } func func4()(a1 int,a2 int) { /** 输出: a1:12 a2:13 */ a1=12 a2=13 return } func func5()(a1 int,a2 int) { /** 输出: a1:12 a2:0 */ a1=12 a3:=13 fmt.Println("temp var",a3) return }
2.3 空白符_
如果不需要某个返回值,可以将这个返回值赋值给空白符
2.4 变长参数
类似于Java,变长参数必须作为参数列表中的最后一个,形式如下:
func func6(a int, s... int ) { }
2.5 defer
defer 的用法类似于 Java 的 finally,用于在函数执行完成后进行释放资源的操作;
defer 关键字可以允许程序在 return 之后执行某个语句或者函数;
如果一个函数内有多个 defer,则会按照 defer 的定义顺序的逆序执行;
程序按照语句顺序执行到 defer 位置时,会先计算确定 defer 函数的参数(此处已经计算确定了参数值,后面就算再修改这个参数变量的值也不会影响 defer 函数调用时的参数值 ),然后在程序 return 后执行该函数;
被 defer 的函数可以读取并修改有变量名的返回参数,一般配合匿名函数使用;
示例:
package main import "fmt" func main() { deferOrder() defineDeferParamFuncValue() defineDeferParamValue() fmt.Println(modifyReturnParamValue()) } func trace(s string) string { fmt.Println("entering:", s) return s } func un(s string) { fmt.Println("leaving:", s) } func deferOrder() { /** 输出: in func deferOrder a2 a1 */ defer fmt.Println("a1") fmt.Println("in func deferOrder") defer fmt.Println("a2") } func defineDeferParamFuncValue() { /** 输出: entering: func defineDeferParamFuncValue in func defineDeferParamFuncValue leaving: func defineDeferParamFuncValue */ // 程序执行到此处时,会先计算确定 defer 函数的参数,然后在程序 return 后执行该函数; defer un(trace("func defineDeferParamFuncValue")) fmt.Println("in func defineDeferParamFuncValue") } func defineDeferParamValue() { /** 输出: 0 */ // defer 函数的参数在计算确定之后,即使参数发生变化,对已经 defer 函数的参数也没有影响 i:=0 defer fmt.Println("define defer param value:",i) i+=1 } func modifyReturnParamValue() (x int) { defer func() { x++ }() x = 2 return 3 }