> 文章列表 > Go语言面试题--基础语法(27)

Go语言面试题--基础语法(27)

Go语言面试题--基础语法(27)

文章目录

    • 1.下面这段代码输出什么?
    • 2.下面这段代码输出什么?
    • 3.下面这段代码输出什么?

1.下面这段代码输出什么?

func main() {var a = [5]int{1, 2, 3, 4, 5}var r [5]intfor i, v := range a {if i == 0 {a[1] = 12a[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]

range 表达式是副本参与循环,就是说例子中参与循环的是 a 的副本,而不是真正的 a。就这个例子来说,假设 b 是 a 的副本,则 range 循环代码是这样的

for i, v := range b {if i == 0 {a[1] = 12a[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]intfor i, v := range &a {if i == 0 {a[1] = 12a[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 修改后的值。

2.下面这段代码输出什么?

func change(s ...int) {s = append(s, 3)
}func main() {slice := make([]int, 5)slice[0] = 1slice[1] = 2change(slice...)fmt.Println(slice)change(slice[0:2]...)fmt.Println(slice)
}

参考答案及解析:

[1 2 0 0 0]
[1 2 3 0 0]

知识点:可变函数、append()操作。Go 提供的语法糖…,可以将 slice 传进可变函数,不会创建新的切片。第一次调用
change() 时,append() 操作使切片底层数组发生了扩容,原 slice 的底层数组不会改变;第二次调用change()
函数时,使用了操作符[i,j]获得一个新的切片,假定为 slice1,它的底层数组和原切片底层数组是重合的,不过 slice1
的长度、容量分别是 2、5,所以在 change() 函数中对 slice1 底层数组的修改会影响到原切片。

Go语言面试题--基础语法(27)

3.下面这段代码输出什么?

func main() {var a = []int{1, 2, 3, 4, 5}//区别var r [5]intfor i, v := range a {if i == 0 {a[1] = 12a[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]

这道题是第1题的一个解决办法,这的 a 是一个切片,那切片是怎么实现的呢?切片在 go 的内部结构有一个指向底层数组的指针,当 range 表达式发生复制时,副本的指针依旧指向原底层数组,所以对切片的修改都会反应到底层数组上,所以通过 v 可以获得修改后的数组元素。