函数传递机制
func add(a int) int {
a++
return a
}
func addo(a *int) int {
*a++
return *a
}
func main() {
x := 3
fmt.Println("x=", x, " &x=", &x)
y := add(x) //执行add实际上修改的是x的副本
fmt.Println("x=", x, " y=", y) //输出的还是x原来的值,改变的是副本y
z := addo(&x) //执行addo函数,实际上修改的是x的值
fmt.Println("x=", x, " z=", z) //输出的x已经被修改
fmt.Println("&x=", &x) //x的地址还是原来的
}
结果:
x= 3 &x= 0xc0000140a8
x= 3 y= 4
x= 4 z= 4
&x= 0xc0000140a8
传指针最明显的三点好处:
1.传指针使得多个函数能操作同一个对象
2.传指针比较轻量级(8B),毕竟只传递内存地址,可以用指针传递体积大的结构体。如果传递值,在每次创建副本上面就会花费相对较多的系统开销(内存和时间),所以当传递较大的结构体时候,用指针是一个明智的选择。
3.传递指针给函数不但可以节省内存(因为没有复制变量的值),而且赋予了函数直接修改外部变量的能力,所以被修改的变量不在需要使用 return 返回。
func main() {
n := 0
res := &n
muliply(2, 4, res)
fmt.Println("Result:", *res)
fmt.Println("n的地址:", &n)
fmt.Println("n的值:", n)
fmt.Println("res直接打印:", res)
fmt.Println("res的地址:", &res)
}
func muliply(a, b int, res *int) {
*res = a * b
}
res是一个指向int变量的指针,通过这个指针,在函数内修改了这个int变量的值。
defer与跟踪
defer延迟语句可以在函数中添加多个,当函数执行到最后(return语句执行之前),这些defer语句会按照后进先出的顺序执行(类似栈,先进后出)。
举个方便的小例子:
func ReadWrite()bool{
file.Open("file")
defer file.Close() //文件打开和关闭都放在一起写不容易遗漏。其他语言可能得写两句,而且关闭是之后的操作,可能造成遗忘出错
}
先进后出类似栈的进出
func main() {
for i:=0;i<5;i++{
defer fmt.Println(i)
}
}
结果:
4
3
2
1
0
关于defer,return和返回值之间的执行顺序
1.函数值被命名
func a() int {
var i = 1
defer func() {
i++
fmt.Println("defer2:", i)
}()
defer func() {
i++
fmt.Println("defer1:", i)
}()
return i
}
结果:
defer1: 2
defer2: 3
return: 1
2.有命名返回值情况下
func main() {
fmt.Println("return:", b())
}
func b() (i int) {
defer func() {
i++
fmt.Println("defer2:", i)
}()
defer func() {
i++
fmt.Println("defer1:", i)
}()
return i
}
结果:
defer1: 1
defer2: 2
return: 2
跟踪
defer经常用于代码跟踪
func trace(s string)string{
fmt.Println("开始执行:", s)
return s
}
func un(s string){
fmt.Println("结束执行:", s)
}
func main() {
b()
}
func a() {
defer un(trace("a")) //初始化defer函数的参数,所以输出trace()的结果
fmt.Println("a的逻辑代码")
}
func b() {
defer un(trace("b"))
fmt.Println("b的逻辑代码")
a()
}
func trace(s string) string {
fmt.Println("开始执行:", s)
return s
}
func un(s string) {
fmt.Println("结束执行:", s)
}
结果:
开始执行: b
b的逻辑代码
开始执行: a
a的逻辑代码
结束执行: a
结束执行: b