Go面试题30
1: 下面这段代码输出什么?
func f(n int) (r int) {
defer func() {
r += n
recover()
}()
var f func()
defer f()
f = func() {
r += 2
}
return n + 1
}
func main() {
fmt.Println(f(3))
}
2: 下面这段代码输出什么?
func main() {
var a = [5]int{1,2,3,4,5}
var r[5]int
for i, v := range a {
if i == 0 {
a[1] = 12
a[2] = 13
}
r[i] = v
}
fmt.Println("r = ", r)
fmt.Println("a = ", a)
}
参考答案及解析
1: 答案及解析: 7
. 根据我们之前提到的三步拆解法
. 第一步执行 r = n + 1
,接着执行第二个defer
,由于此时f()
未定义,引发异常,随机执行第一个defer
,异常被recover()
, 程序正常执行,最后return
. 拆解如下:
func (n int) (r int) {
r = n + 1 // 返回值赋值
f() // 执行第二个defer 由于f 未定义引发异常
recover() //执行第一个defer
return // 空的return 返回
}
2: 答案及解析:
r = [1 2 3 4 5]
a = [1 12 13 4 5]
range
表达式是副本参与循环,就是说例子中参与循环的是a
的副本,而不是真正的a
. 就这个例子来说, 假设b
是a
的副本, 则range
循环代码是这样的:
for i, v := range b {
if i == 0 {
a[1] = 12
a[2] = 13
}
r[i] = v
}
因此无论a
被如何修改, 其副本b
依旧保持原值,并且参与循环的是b
,因此v
从b
中取出的仍旧是a
的原值,并非修改后的值.
如果想要r
和 a
一样输出,修复办法:
func main() {
var a = [5]int{1,2,3,4,5}
var r [5]int
for i, v := range &a {
if i == 0 {
a[1] = 12
a[2] = 13
}
r[i] = v
}
fmt.Println("r = ", r)
fmt.Println("a = ", a)
}
输出:
r = [1 12 13 4 5]
a = [1 12 13 4 5]
修复代码中, 使用*[5]int
作为range
表达式, 其副本依旧是一个指向原数组a
的指针,因此后续所有循环中均是&a
指向的原数组亲自参与的, 因此v
能从&a
指向的原数组中取出a
修改后的值.
「真诚赞赏,手留余香」
真诚赞赏,手留余香
使用微信扫描二维码完成支付