前端仔有点学不明白 golang 的 defer

67 天前
 zhengfan2016

背景:这个地方的 test-1 题 https://golang.dbwu.tech/traps/defer_exam/

如下 test-1 题,使用具名返回值,defer 就能修改 t 的值

package main

func foo(n int) (t int) {
	t = n
	defer func() {
		t += 3
	}()
	return t
}

func main() {
	println(foo(1))
}

但是我不使用具名,就算我把 t 移到最外层的作用域,defer 也改变不了 t 的值,我试着不在 defer 作用域内,就可以修改

package main

var t int

func foo(n int) int {
	t = n
	defer func() {
		t += 3
	}()
	return t
}

func main() {
	println(foo(1))
}

感觉被绕晕了

4147 次点击
所在节点    Go 编程语言
46 条回复
lesismal
67 天前
不知道谁带头搞的这些题啊,我一个都不会做、只能运行跑结果来看才知道答案。
但是我从来都不会这样用 defer 导致这种问题啊,搞这些题的人是吃得太饱了吗!
wunonglin
67 天前
虽然我知道有些基础应该会,不过我写了 go3 、4 年确实没碰到过这种场景。我麻了 hhhhh
rahuahua
67 天前
下面这个 defer 也是能修改 t 的值,只是返回值已经拷贝了 t 的值,不受影响了
maxwellz
67 天前
返回值如果没有设置名称,defer 中的值不会改变返回值
kcross
67 天前
给你看个好玩的,你试试这个

package main

var t int

func foo(n int) (t int) {
t = n
defer func() {
t = t+ 3
}()
return
}

func main() {
println(foo(1))
}
uion
67 天前
不会 go ,盲猜一下。参数有引用,具名参数返回时先运行 defer 。不使用具名应该是直接返回了再 defer ?
zhengfan2016
67 天前
@maxwellz 对的,我就想问这个问题,为什么不设置名称 defer 就改不动呢
R136a1
67 天前
值传递和引用传递的区别?
ninjashixuan
67 天前
想学这类边界技巧可以关注 go101 的作者。
NessajCN
67 天前
https://go.dev/blog/defer-panic-and-recover

"3. Deferred functions may read and assign to the returning function's named return values."

纯粹就是 named return 特性,死记就好了
sardina
67 天前
谁要在开发中这么写代码 小心被打
zhengfan2016
67 天前
@sardina 哈哈,我感觉你可以整理一个 awesome golang 容易挨打的代码片段,让新手村的 xdm 学习
vincentWdp
67 天前
```
func foo(n int) (t int) {
t = n
```
换成
```
func foo(n int) int {
t := n
```
ChrisFreeMan
67 天前
@lesismal 看到你也不会我就放心了
zhengfan2016
67 天前
@NessajCN 原来如此
sardina
67 天前
第一个例子 return 是先把返回值存到临时变量里,然后 defer 再修改也改不到临时变量
第一个例子因为返回值有命名,所以 return 是把返回值存到这个命名里里,然后 defer 就可以修改了
总的来说就是 return 先设置返回值 然后再执行 defer ,然后函数返回
https://www.cnblogs.com/saryli/p/11371912.html 可以看这个
peteretep
67 天前
后端仔都不这么写的。不要起步就走犄角旮旯了。没有实际意义的。

这个和 c++考试 i++++ 、 ++i++ 的题目有什么区别吗?

defer 只用来释放资源,其他使用正常的程序算法解决。
maxwellz
67 天前
@zhengfan2016 #7 貌似和 defer 的特性有关系了,这块太久没看了,忘了
Liv1Dad
67 天前
很简单啊,defer 放到 一个栈里面。
defer func() { t+=3}() 这个匿名函数 放入到栈中, 等 function 结束时运行。
第一个 函数返回 t, 函数结束后继续执行了 t+=3 。
第二个 函数返回 t 的值,数据结束后继续执行了 t+=3, 此时的 t 和函数返回结果 没有关系。
Liv1Dad
67 天前
@wunonglin #2 我代码经常写 defer ,比如打开文件需要 close, 或者回收 chan, 还有数据库事物结束。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://yangjunhui.monster/t/1122635

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX