Go学习随笔(八)函数参数传递机制\defer和跟踪语句

函数传递机制

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章