浅谈Go与习题(十)

104 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第33天,点击查看活动详情

今天来学习下Go常见的习题问题(十),也是面试中可能会遇到的,让我们来一起学习吧~

循环次数

观察下列代码,判断是否会出现死循环?

func main() {
    v := []int{1, 2, 3}
    for i := range v {
        v = append(v, i)
    }
}

参考答案:不会出现死循环,可以正常结束,循环次数在一开始就确定为3次,循环内改变切片的长度,不会影响循环次数,我们可以通过fmt.Println输出看下结果,是正常可以结束的。

image.png

观察下列代码,判断输出结果是什么?

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))
}

参考答案:输出结果为7,第一步先执行r = n + 1 ,紧接着执行第二个函数,由于此时函数未被定义,抛出异常,执行第一个函数r +=n,异常被recover()捕获,程序正常执行最后return 变量r,程序结束。

range拷贝

观察下列代码,判断输出结果是很么?

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 2 3 4 5] a = [1 12 13 4 5],因为这里循环内是a的副本,无论如何修改原数组a的值,不会改变v的值,因为是进行拷贝后的值,所以想要数组r也有同样的修改效果,需要将代码修改成如下所示:

func main() {
    var a = [5]int{1, 2, 3, 4, 5}
    var r [5]int
    //这里加上指向原数组a的指针
    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)
}

或者将数组a改成切片,因为切片在go的内部结构中有一个指向底层数组的指针,当拷贝的值发生改变时候,副本的指针依旧指向原来的底层数组,所以对切片的修改会同步到底层数组上,所以在通过v获取到的就是修改后的值

func main() {
    var a = []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)
}

总结

今天浅谈了Go的习题(十),主要介绍了GO面试中会出现的问题,接下来会继续分享其他的习题的相关知识,对于一个刚入门的我来说,还有许多地方需要学习,有错误的地方欢迎大家指出,共同进步!!,新年快乐,明年继续加油!!!