看了defer这一小节 我对函数理解

来源:9-6 defer机制你忽略了很多细节

城中城

2022-05-10

如下面代码
为什么会产生 不同的值呢
我个人 理解 是 retrun 都是 返回的值 都是 值传递 都是复制出来的值
只不过 如果复制的值是指针 在外部做了处理 就 " * " 取值运算符
" * " 就相当于 一个函数 通过 指针的值 重新运算出 b 的值

func f1() int {
	x := 10
	defer func() {
		x++
	}()
	//temp_data := x	// x是值传递
	return x
}

func f2() *int {
	a := 10
	b := &a
	defer func() {
		*b++
	}()
	//temp_data := b	// 引用传递
	return b
}

func main() {
	fmt.Println(f1()) // 是不是就意味着 defer中
	fmt.Println(*f2())
}

指针:
只不过 是 重新向 内存申请了一个空间 用来保存 值的地址
值的地址 也有地址 这个 值的地址 指向 值
(值的地址的 地址) 指向 值的地址

func f2() *int {
	a := 10
	b := &a
	defer func() {
		*b++
	}()
	//temp_data := b	// 引用传递
	fmt.Println("函数内 值的地址的地址: ", &b) // 这里 值的地址 的地址 与 main 值的地址 的地址 不一致 说明了 return 都会copy 一份值
	return b
}

func main() {
	z := f2()
	fmt.Println("值的地址的地址: ", &z)
	//fmt.Println(&&z)		// 不存在无限套娃  因为  值的地址的地址 的地址 没有申请空间
	fmt.Println("值的地址的地址指向的 值的地址: ", *&z)
	fmt.Println("值的地址: ", z)
	fmt.Println("值: ", *z)
}

可以运行上面代码看出
函数内 值的地址的地址 与 函数外 值的地址的地址 不一致
所以 我猜测 return 的 都是 copy 出来的值 只不过 有些值是固定不变(比如指针)
只不过 通过 " * " 解析出 它的值 罢了


后续 我 看了一下 slice 切片 为什么说是 引用传递呢
我特意去打印了 slice的地址

	oldSilce := []int{1, 2, 3}
	newSilce := oldSilce
	fmt.Printf("%p\n", &oldSilce)
	fmt.Printf("%p\n", &oldSilce[0])
	fmt.Printf("%v\n", &oldSilce[0])
	fmt.Printf("%p\n", oldSilce)
	fmt.Println("------------------------------")
	fmt.Printf("%p\n", &newSilce)
	fmt.Printf("%p\n", &oldSilce[0])
	fmt.Printf("%v\n", &oldSilce[0])
	fmt.Printf("%p\n", oldSilce)

输出的结果是
0xc000004120 // 这个是 slice 的 真实地址(我是这么认为的)
0xc000012180 // 这个是 slice 的 元素0 的 地址
0xc000012180 // 这个是 我为了验证一下 %p 是打印地址
0xc000012180 // 这个是 slice 默认地址 走元素0的地址 (毕竟底层是数组)
------------------------------
0xc000004138
0xc000012180
0xc000012180
0xc000012180

从这打印 看出 其实 slice 也copy了 一份 开辟了新的内存空间
只不过 新的内存空间 存储的是 元素的地址值
打印 为什么不是 地址呢 (类似python name 这个魔法方法 给我们显示 值)
这导致 修改 里面的元素
因为 地址不变 修改地址指向的 值 所以 显示上看 值也随之改变

并且我打印了 slice 占用空间的大小 得出的字符是 24
无论添加多少元素 都是 24字符
说明 slice 存储的确实是一个 地址值

老师你看看我的理解对不对
毕竟是个人猜测的

写回答

1回答

bobby

2022-05-11

这个内容有些地方没太看明白,我给你总结一下吧: go中所有都是值传递, slice, 指针,结构体,所有都是值传递,

指针之所以能达到指针的效果,是因为指针本身也是一个值对象,不过里面存储的是一个真实的地址,所以你复制多少份这个地址都能找到正确的地址并修改,struct就不用多说了,slice比较特殊,slice本质是结构体,所以也是值传递,不过这个结构体底层指向的是一个数组,这个数组不会复制,所以还是改的原本的数组,但是当slice扩容的时候就不会继续影响原来的值了

0
0

Go+Python打造电商系统 自研微服务框架 抓紧高薪机遇

快速转型Go工程师,成为具备双语言后端能力的开发者

508 学习 · 530 问题

查看课程