Go: For-Loop-Variable 适合面试的小问题

2023-12-29 12:12:03 +08:00
 GopherDaily

在面试的过程中, 如果恰好遇到对方日常也使用 Go 做为主力语言, 我会选择一些简单而可扩展的问题交流下双方对 Go 的熟悉程度.

我喜欢的一个问题是让面试者告诉我下述代码的运行结果:

func main() {
	for i := 0; i < 3; i++ {
		go func() {
			fmt.Println(i)
		}()
	}

	time.Sleep(time.Second)
}

正确的答案应该是: 乱序输出三个数字. 对于三种错误答案: 输出 1, 2, 3; 输出三个数字; 乱序输出 1, 2, 3; 都可以通过反问再给予一次机会.

进一步的, 我们可以询问如何让其至少将 1, 2, 3 都输出一次. 大多数时候, 我们的得到的答案会是将 i 做为参数传入. 此时我喜欢再追问, 下述代码中 i := i 的写法是否正确.

func main() {
	for i := 0; i < 3; i++ {
		i := i
		go func() {
			fmt.Println(i)
		}()
	}

	time.Sleep(time.Second)
}

我并不认为这是一个 Language Lawyer 问题, 由于 Go 中 for 循环的特殊实现方式, i := i 这种方式在 Go 中是普遍存在的.

极少数情况下, 我们可以再讨论下上述例子的原因, 允许面试者有更大的发挥机会. 其中包括的点有:

我们在下述例子中看到, i 和 v 的内存地址始终未曾改变:

~ cat main.go
func main() {
    nums := []int{1, 2, 3}
    for i, v := range nums {
        fmt.Println(&i, &v)
    }
}
~ go run main.go
0x1400009a018 0x1400009a020
0x1400009a018 0x1400009a020
0x1400009a018 0x1400009a020
~ cat main.go | grep -A 7 "func fnVarScope"
func fnVarScope() {
    s := "hello world"
    {
        s := 10
        fmt.Println("s:", s)
    }
    fmt.Println("s:", s)
}
~ go run main.go
s: 10
s: hello world

Source: https://github.com/j2gg0s/j2gg0s/blob/main/_posts/2023-12-29-Go%3A%20For-Loop-Variable%20%E9%80%82%E5%90%88%E9%9D%A2%E8%AF%95%E7%9A%84%E5%B0%8F%E9%97%AE%E9%A2%98.md

5996 次点击
所在节点    Go 编程语言
33 条回复
MoYi123
2023-12-29 15:17:56 +08:00
你这个 c++问 ub 有什么区别?
RogerBen
2023-12-29 15:18:54 +08:00
@xiaxiaocao
我靠,为啥是 0 呢
ememem0
2023-12-29 15:19:19 +08:00
自己掌握的知识都是错的,还面试别人。面试者真的惨。
geelaw
2023-12-29 16:14:45 +08:00
@GopherDaily #14 错误的方式可以有很多,没有必然理由认为你的错误答案程度更轻,建议不要和别人玩“揣摩出题人意思”的游戏。

#15 你可能没有理解我的意思。

>我们在下述例子中看到, i 和 v 的内存地址始终未曾改变: ...
>另外 i 和 v 的地址未曾改变不能证明任何事情,即使每次迭代的变量是新的,编译器也可以证明复用旧的内存位置没问题,于是优化之后会看到相同的地址。

引述第一段内容,阅读后揣摩得出:这段话是想要通过地址不改变 (A) 证明迭代变量每次都是同一个 (B),即论证 A => B ,并观察到 A ,因此推出 B 。
引述第二段内容,意思是 A => B 的论证不恰当,并不是说 A => B 这个命题本身不真。

换言之,A 对论证 B 是无意义的,论证 B 的惟一方式是阅读 Go 的定义。
yxd19
2023-12-29 16:30:53 +08:00
@geelaw 我不会写 go 啊。但是按你的说法如果我已经把一个变量传进一个闭包了,为啥复用这个变量的内存位置没问题啊?
RedisMasterNode
2023-12-29 16:36:54 +08:00
第一题不是 3 3 3 吗
monkeyWie
2023-12-29 16:39:45 +08:00
这种官方狗屎设计导致的 bug ,有什么好面的,新版本里都要修复了
geelaw
2023-12-29 16:45:28 +08:00
@yxd19 #25 你可能没有仔细阅读楼主的内容,请看第三段代码片段,那里面没有闭包。
yxd19
2023-12-29 16:48:59 +08:00
@geelaw 嗷嗷 确实 那没毛病
rrfeng
2023-12-29 17:28:08 +08:00
@xiaxiaocao

var x = 8
var a byte = 1 << x / 2
这样 a 就是 0 ,难道是为了省空间,计算 1<<x 的时候直接在 a 上操作,导致溢出了??

如果是 const x = 8 的话,const 会在编译的时候计算完 1<<x/2 的结果,于是能够放进 byte 里不会溢出。
defunct9
2023-12-29 17:44:49 +08:00
javascripts 应该是 3 3 3
faker1
2023-12-29 22:50:05 +08:00
这个面试者太惨了,
ensonmj
2023-12-30 10:50:32 +08:00
go 八股文

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

https://yangjunhui.monster/t/1004376

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

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

© 2021 V2EX