// https://tour.golang.org/moretypes/10
package main
import "fmt"
func main() { s := []int{1, 2, 3, 4, 5, 6}
s = s[1:4]
fmt.Println(s)
s = s[:5]
fmt.Println(s) // 这里 s 接上面的起点 2,但是终点却是 6 ?
s = s[1:]
fmt.Println(s)
}
////output
[2 3 4]
[2 3 4 5 6]
[3 4 5 6]
1
doylecnn 2020-01-06 19:11:29 +08:00 via Android
下标从 0 开始呀,哪里坑了?
|
2
catror 2020-01-06 19:12:27 +08:00 via Android
这是设计,边界不超过 cap 就行
|
3
ArJun 2020-01-06 19:15:02 +08:00
这种赋值操作一般不推荐吧,你使用的始终是一个对象
|
4
lostpg 2020-01-06 19:23:34 +08:00 via Android
下表从零开始,end 的值是末尾元素下标+1。这种用法有梗的
|
6
petelin 2020-01-06 19:24:54 +08:00 via iPhone
第二个用法我其实挺惊讶的
我一直以为边界是 len 这样看是 cap |
7
saltsugar OP |
8
ethego 2020-01-06 19:53:32 +08:00
数组越界了,所以取到了 slice 外面的东西,这时候是未定义行为,取到任何东西都不奇怪。只是这里 slice 没有发生拷贝,取到了原地址后面的东西了。
|
9
ethego 2020-01-06 20:06:18 +08:00
至于取分片为什么没有拷贝或者不做越界检查当然是为了性能,所以挺合理的
|
10
zhyl 2020-01-07 10:19:28 +08:00
切片和数组是不同的. 两种类型能够索引数据的范围都是在 len(x)之内的.
但是切片可以通过重新切片来扩展它的 len, 重新切片允许的范围是其底层数组决定的, 它等于切片的 cap. 不存在数组越界和未定义行为这种说法. |
12
zhuyuefeng 2020-01-08 23:24:33 +08:00
这么解释不知道合不合适:
// origin s := []int{1, 2, 3, 4, 5, 6} s = s[1:4] // 此时 s 是原数组的切片,其内容就是[2 3 4],索引 index 1, 2, 3 的值 // 但原数组的 cap 比现在的切片大,所以目前是可以扩展的 // [2 3 4] fmt.Println(s) s = s[:5] // 进行重切片,此时发现原切片不够大,但底层数组的 cap 够,也就增加了后面的 6,就是 index=4 的值 fmt.Println(s) // [2 3 4 5 6] s = s[1:] // 此时又重新切片 去掉第一个元素 index=0,也就是 2,那么返回的数据就是[3 4 5 6] fmt.Println(s) // [3 4 5 6] |
13
saltsugar OP 谢谢楼上各位的讨论和回答。总结一下
package main import ( "fmt" ) func main() { fmt.Println("Hello, playground") a := []int{1,2,3,4,5,6} printSlice(a) b := a[1:3] b[0] = 0 printSlice(b) c := b[:3] c[0] = 0 printSlice(c) //d := c[-1:] 可惜不能往前扩 //printSlice(d) d := c[1:4] d[0] = 0 printSlice(d) e := d[1:4] //通过小切片来移动窗口处理数据还是挺方便的。 e[0]=0 printSlice(e) printSlice(a) } func printSlice(s []int) { fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s) } Hello, playground len=6 cap=6 [1 2 3 4 5 6] len=2 cap=5 [0 3] len=3 cap=5 [0 3 4] len=3 cap=4 [0 4 5] len=3 cap=3 [0 5 6] len=6 cap=6 [1 0 0 0 5 6] |
14
saltsugar OP 另外,append 后,变量指向新数组实例了。
|