回答for...range 遍历数组与切片的区别等三个Go语言问题
请看下面这段代码:
package main
import (
"fmt"
)
func f(n int) (r int) {
defer func() {
r += n
recover()
}()
var f func()
defer f()
f = func() {
r += 8
}
return n + 2
}
func main() {
fmt.Println(f(3))
}
程序运行结果是:
8
为什么呢?执行f(3)时,这段代码会先执行return中的n+2,然后执行defer语句,因为defer语句是先进后出,故先执行defer f(),然后因为此时f()未定义,所以会导致panic异常读书,不过,别急,我们下一个defer语句使用recover()将异常回收了,然后r += n,也就是r加3,因为r+8未执行,所以和是3+2+3=8.
二、切片底层数组的一个有关问题
再看下面这段代码:
package main
import (
"fmt"
)
func change(s ...int) {
s = append(s, 8)
}
func main() {
slice := make([]int, 5, 5)
slice[0] = 0
slice[1] = 1
fmt.Println(slice)
change(slice...)
fmt.Println(slice)
change(slice[0:2]...)
fmt.Println(slice)
change(slice[0:3]...)
fmt.Println(slice)
change(slice[0:4]...)
fmt.Println(slice)
change(slice[0:5]...)
fmt.Println(slice)
}
你认为输出结果是什么?
下面是输出结果。你答对了吗?
[0 1 0 0 0]
[0 1 0 0 0]
[0 1 8 0 0]
[0 1 8 8 0]
[0 1 8 8 8]
[0 1 8 8 8]
答对的小伙伴可以看下一点啦~
答错的小伙伴来听我解释一下吧~
如果函数change(s ...int)的参数类型使用...
,可以将slice切片传入而不会新建切片。这里第一次调用change()函数前,创建的切片容量和长度是相等的,所以调用change()函数后,切片进行扩容,会导致生成新的切片,8也加在新的切片上,原来的切片不会发生变化。
change(slice[0:2]...)
fmt.Println(slice)
这行代码使用[0:2]截取生成了一个新的切片,但是它的底层数组与之前的切片的底层数组是一样的,不过新切片的长度是2,而之前切片的长度是5.所以在这个切片上append元素我们打印旧切片slice能够看到,也就是:
[0 1 8 0 0]
然后我们一直截取一直增加,直到:
change(slice[0:5]...)
fmt.Println(slice)
此时切片的容量和长度已经加到一致了,再append来添加元素就会导致扩容,而导致底层数组变化。所以再次打印slice切片,就会还是:
[0 1 8 8 8]
三、for...range 遍历数组与切片的区别
package main
import (
"fmt"
)
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] = 8
a[2] = 8
}
r[i] = v
}
fmt.Println("r = ", r)
fmt.Println("a = ", a)
}
先来看一看运行结果:
r = [1 2 3 4 5]
a = [1 8 8 4 5]
我们可以看到,遍历时保存的r数组内的值与最终输出的数组不一致,我们前面的文章说过,这是因为for...range遍历数组时,会生成一个副本,然后遍历这个副本,所以我们在循环中修改数组的值并不会修改副本的值,所以导致两个数组结果不一致。
而切片就不一样了,我们来看一看切片会有什么运行结果:
package main
import (
"fmt"
)
func main() {
var a = []int{1, 2, 3, 4, 5}
var r [5]int
for i, v := range a {
if i == 0 {
a[1] = 8
a[2] = 8
}
r[i] = v
}
fmt.Println("r = ", r)
fmt.Println("a = ", a)
}
这是运行结果:
r = [1 8 8 4 5]
a = [1 8 8 4 5]
我们可以看到两个是相同的,这是因为虽然是副本,但是指向的是同一个底层数组,因此修改副本的底层数组也会修改原切片的底层数组。
- 点赞
- 收藏
- 关注作者
评论(0)