这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天。
函数是Go语言的一等公民,其封装了一系列的指令操作。
1. 函数
函数的定义
func 函数名 (形参列表) (返回值列表) {
函数体
}
func main() {
println(add(1, 2))
println(calculate(1, 2, 3))
}
func add(a int, b int) int {
sum := a + b
return sum
}
func calculate1(a, b, c int) (int, int) {
sum := a + b + c
avg := sum / 3
return sum, avg
}
func calculate2(a, b, c int) (sum int, avg int) {
sum = a + b + c
avg = sum / 3
return
}
// 可变参数列表
func sum(nums ...int) int {
sum := 0
for _, n := range nums {
sum += n
}
//for i := 0; i < len(nums); i++ {
// sum += nums[i]
//}
return sum
}
- 参数若类型一致,可以向上面那样声明多个参数
- 返回值支持多个返回值,在 return 时按顺序赋值返回
- 若返回值定义了变量名,则 return 后面可以为空
- Go 的函数没有重载,参数默认值,可选参数
- 函数也是一种数据类型,可以作为参数传递和返回值
反射获取函数的一些信息:
fmt.Println(reflect.TypeOf(add))
// func(int, int) int
fmt.Println(
runtime.FuncForPC(
reflect.ValueOf(add).Pointer(),
).Name(),
)
// main.add
2. init 函数
Go 语言的每个源文件中都可以包含一个 init 函数,该函数在 main 函数之前被调用,用以完成一些初始化操作。
- 一个 Go 源文件的执行顺序:1. 包变量的定义和初始化;2.
init函数;3.main函数
package main
import "fmt"
var a = variable()
func variable() int {
fmt.Println("包变量的初始化时执行 variable")
return 1
}
func init() {
fmt.Println("init")
}
func main() {
fmt.Println("main")
}
// 包变量的初始化时执行 variable
// init
// main
- 当
import其他源文件,会按引入顺序依次执行,
package beimport
import "fmt"
var A = variable()
func variable() int {
fmt.Println("beimport.go#variable")
return 1
}
func init() {
fmt.Println("beimport.go#init")
}
package main
import "fmt"
import "awesomeProject/funcdemo/beimport"
var a = variable()
func variable() int {
fmt.Println("variable")
return 1
}
func init() {
fmt.Println("init")
}
func main() {
fmt.Println("main")
fmt.Println(beimport.A)
}
// beimport.go#variable
// beimport.go#init
// variable
// init
// main
// 1
3. 闭包
如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包
func Accumulator(init int) func(int) int {
n := init
return func(x int) int {
n += x
return n
}
}
func main() {
accumulator := Accumulator(10)
fmt.Println(accumulator(1)) // 11
fmt.Println(accumulator(2)) // 13
fmt.Println(accumulator(3)) // 16
}
accumulator := Accumulator(10)这次调用结束后,一个函数变量被赋值给了accumulator并成为了一个闭包- 在闭包
accumulator中,函数Accumulator的局部变量n逃逸了。n的生命周期没有随着函数Accumulator的作用域的结束而结束。
4. defer
当函数执行到 defer 语句时,不会立即执行该语句;而是将该语句压入一个 defer 栈中。
然后再函数 return 之前,将 defer 栈中压入的语句一条一条弹出来执行。
func main() {
fmt.Println(1)
fmt.Println(2)
defer fmt.Println("defer 1")
defer fmt.Println("defer 2")
defer fmt.Println("defer 3")
fmt.Println(3)
fmt.Println(4)
}
// 1
// 2
// 3
// 4
// defer 3
// defer 2
// defer 1
- 入栈时,函数的入参也会被一起拷贝好放入栈中
func main() {
n := 0
defer fmt.Println(n) // 0
n = 1
}
可以用指针来接受新的值
func main() {
n := 0
p := &n
defer testDefer(p) // 1
n = 1
}
func testDefer(p *int) {
fmt.Println(*p)
}