Go面试题30

Posted by     "" on Friday, December 27, 2019

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. 就这个例子来说, 假设ba的副本, 则range循环代码是这样的:

for i, v := range b {
    if i == 0 {
        a[1] = 12
        a[2] = 13
    }
    r[i] = v 
}

因此无论a被如何修改, 其副本b依旧保持原值,并且参与循环的是b,因此vb中取出的仍旧是a的原值,并非修改后的值.

如果想要ra 一样输出,修复办法:

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修改后的值.

「真诚赞赏,手留余香」

Richie Time

真诚赞赏,手留余香

使用微信扫描二维码完成支付