Slice
切片是对数组的抽象。Go语言中不叫数组,而是一个结构体。
type slice struct {
array unsafe.Pointer //指向存放数据的数组指针
len int //长度有多大
cap int //容量有多大
}
示例一
foo := make([]int, 5)
printSlice(foo)//len:5, cap= 5, [0 0 0 0 0]
foo[3] = 42
foo[4] = 100
printSlice(foo)//len:5, cap= 5, [0 0 0 42 100]
bar := foo[1:4]
printSlice(bar)//len:3, cap= 4, [0 0 42]
bar[1] = 99
printSlice(bar)//len:3, cap= 4, [0 99 42]
func printSlice(slice []int) {
fmt.Println("len:", len(slice), "cap:", cap(slice))
}
- 先声明了一个foo的slice,其中长度和容量都是5
- 给索引3、4赋值分别为42,100
- 对foo做切片,起始索引1,终止索引4(不包含4),并赋值给bar
- len为3;cap为foo.leng - 1(起始索引)
示例二append
a := make([]int, 32)
printSlice(a)//len:32, cap= 32, [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
b := a[1:16]
printSlice(b)//len:15, cap= 31, [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
a[2] = 66
printSlice(a)//len:32, cap= 32, [0 0 66 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
printSlice(b)//len:15, cap= 31, [0 66 0 0 0 0 0 0 0 0 0 0 0 0 0]
a = append(a, 1)
a[2] = 42
fmt.Println("由于a的cap不够,需要扩容,扩容后的a会重新分配内存。此时修改a[2]=42,则b[1]是不会受到影响的")
printSlice(a)//len:33, cap= 64, [0 0 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]
printSlice(b)//len:15, cap= 31, [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
- 声明一个长度、容量32的切片
- 把 a[1:16] 的切片赋给 b,此时a,b的内存是共享的。
- 此时append操作,a已达到最大容量,会对a重新分配内存,此时a和b的内存不在共享。
示例三
path := []byte("AAAA/BBBBBBBBB")
sepIndex := bytes.IndexByte(path,'/')
dir1 := path[:sepIndex]
dir11 := path[:sepIndex:sepIndex] //Full Slice Expression,
dir2 := path[sepIndex+1:]
fmt.Println("dir1 =>",string(dir1)) //prints: dir1 => AAAA
fmt.Println("dir2 =>",string(dir2)) //prints: dir2 => BBBBBBBBB
fmt.Println("dir3 =>",string(dir11)) //prints: dir2 => AAAA
//相同地址
fmt.Printf("%x\n", &dir1[0])
fmt.Printf("%x\n", &path[0])
//Full Slice Expression
fmt.Printf("%x\n", &dir2[0])//path[:sepIndex:sepIndex] Full Slice Expression,申请新的内存地址
dir1 = append(dir1,"suffix"...)
fmt.Println("dir1 =>",string(dir1)) //prints: dir1 => AAAAsuffix
fmt.Println("dir2 =>",string(dir2)) //prints: dir2 => uffixBBBB
dir11 = append(dir11,"11111"...)
fmt.Println("dir3 =>",string(dir11)) //prints: dir3 => AAAA11111
fmt.Println("dir2 =>",string(dir2)) //prints: dir2 => uffixBBBB
- dir1 和 dir2 共享内存
- dir1有一个append的操作,因为cap足够,于是数据添加到了dir2的空间下。
- dir1 := path[:sepIndex:sepIndex]使用了 Full Slice Expression,最后一个参数叫“Limited Capacity”,于是,后续的 append() 操作会导致重新分配内存。
示例四 深度比较
v1 := data{}
v2 := data{}
fmt.Println("v1 == v2:",reflect.DeepEqual(v1,v2))
//prints: v1 == v2: true
m1 := map[string]string{"one": "a","two": "b"}
m2 := map[string]string{"two": "b", "one": "a"}
fmt.Println("m1 == m2:",reflect.DeepEqual(m1, m2))
//prints: m1 == m2: true
s1 := []int{1, 2, 3}
s2 := []int{1, 2, 3}
fmt.Println("s1 == s2:",reflect.DeepEqual(s1, s2))
//prints: s1 == s2: true