func
函数是通过func
关键字来声明的,基本结构如下:
func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
//这里是处理逻辑代码
//返回多个值
return value1, value2
}
funcName是函数名
如果有多个返回值,建议添加返回值变量名。
变参:指定函数接收不定数量的参数。
func funcName(arg ...int) {}
arg ...int
的所有类型为int
类型,在函数体中arg
是一个int
类型的slice
。
函数传参 要考虑的是传入的参数需不需要改变原始值。
传值:这样只会copy一份参数值,并不会影响到原始值。
传指针:这会对原始值产生作用。
package main
import "fmt"
//简单的一个函数,实现了参数+1的操作
func add1(a *int) int { // 请注意,
*a = *a+1 // 修改了a的值
return *a // 返回新值
}
func main() {
x := 3
fmt.Println("x = ", x) // 应该输出 "x = 3"
x1 := add1(&x) // 调用 add1(&x) 传x的地址
fmt.Println("x+1 = ", x1) // 应该输出 "x+1 = 4"
fmt.Println("x = ", x) // 应该输出 "x = 4"
}
&x
是取变量x
内存地址的指针。
*x
是变量x
进行操作,也叫指针取值。
传指针的好处在哪?
传指针使得多个函数能操作同一个对象。
传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。
如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。
所以当你要传递大的结构体的时候,用指针是一个明智的选择。
Go语言中channel
,slice
,map
这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice
的长度,则仍需要取地址传递指针)
defer
关键字defer
:延迟调用。
关键字 defer 用于注册延迟调用。
这些调用直到 return 前才被执。因此,可以用来做资源清理。
多个defer语句,按先进后出的方式执行。
package main
import "fmt"
//多个defer语句,按先进后出的方式执行。
func main() {
for i := 0; i < 5; i++ {
defer fmt.Println(i)
}
}
输出:
4
3
2
1
0
Process finished with exit code 0