一般的函数
package main
import "fmt"
func add1(x int, y int) int {
return x + y
}
//多个返回值,并直接命名
func add2(x, y int) (r1, r2 int) {
r1 = x + y
r2 = 0
return
}
func main() {
a := add1(1, 2)
b, _ := add2(3, 4)
fmt.Println(a, b)
}
代码说明:
- 函数声明格式:
func 函数名(参数) 返回值{ }
。 - 如果直接命名返回值,直接return即可。
- 可以返回多个值。下划线
_
说明用不到这个返回值,丢弃它。
匿名函数、可变参数函数
package main
import "fmt"
//传入数量可变的参数
func f2(args ...int) {
for index, x := range args {
fmt.Println(index, x)
}
}
func main() {
//匿名函数
f1 := func(x, y int) int {
return x + y
}
a := f1(10, 20)
//a := func(x, y int) int {
// return x + y
//}(10,20)
fmt.Println(a)
f2(1, 2, 3)
// f2([]int{1, 2, 3}...)
}
代码说明:
- 在本例中,匿名函数被赋值给变量
f1
,由f1
进行调用。注释中是直接调用的用法。 - 在本例中,
f2
函数可以接受可变参数,参数“类型”为...int
(其实函数接收的是切片)。 ...
还可以用于调用函数时,表示将切片打散,在本例中,int
类型的切片被打散后,以多个int
类型传入,即传入参数[]int{1, 2, 3}...
等价于传入参数1, 2, 3
。
函数作为参数、defer
package main
import "fmt"
type testFunc func(int, int)
func add(x, y int) {
fmt.Println(x + y)
}
//函数作为参数
func f1(arg1 int, f testFunc) {
f(arg1, 2)
}
func deferTest(arg int) {
fmt.Println(arg)
}
func main() {
f1(1, add)
a := 5
defer deferTest(a)
a = 10
fmt.Println(a)
defer fmt.Println(2222)
}
输出:
3
10
2222
5
代码说明:
- 函数也是一种变量,可以通过
type
定义它,此类函数变量拥有相同类型的参数和返回值。 - 关键字
defer
表示延迟函数,类似于 Java 的finally
语句块,它一般用于释放某些已分配的资源。 - 延迟函数会在
defer
语句所在的函数全部执行完之后(包括return
语句的代码)但还没返回时,再执行。 - 但是并非在调用延迟函数的时候才确定实参,而是当执行
defer
语句的时候,就会对延迟函数的实参进行求值。如在上述例子中,语句defer deferTest(a)
的参数在执行这一语句时就确定了,没有等到最后调用deferTest(a)
的时候再确定。 - 多个
defer
理解为栈即可,先进后出。
两个保留函数
init函数
init
函数不应该有任何返回值类型和参数,也不能显式地调用它,主要用于初始化。
有时候引入一个包,只是为了确保它进行了初始化,而无需使用包中的任何函数或变量,这种情况就可以使用空白标识符 _
,此时只会调用init
函数,举例:
import (
_ "demo/test"
)
在一个文件或包中,你可以有多个 init 函数。在文件中执行 init 函数的顺序和其出现顺序是一致的。
main函数
main函数只能应用于package main,且package main必须包含一个main函数。和init函数一样的是,main函数也不能有任何的参数和返回值。
一个项目中多个go文件的初始化顺序为:
从main
包开始,先初始化引入的包(重复引入的包只初始化一次),以此类推,直到最后被引入的包,初始化这个包的常量、变量和init
函数,往前推直到main
包,最后执行main
函数。