1. slice本质上是基于数组的一种数据结构(struct),是数组的一种透视。
2. slice的数据结构为:
```go
type slice struct {
array unsafe.Pointer
len int
cap int
}
```
请注意, array是一个指针类型。
3. slice作为数组的一部分透视来使用:
```go
testArr := [5]int{0, 1, 2, 3, 4}
sliceFromArr := testArr[1:3]
fmt.Println(sliceFromArr) // [1, 2]
sliceFromArr[0] = 11
fmt.Println(testArr) //[0 11 2 3 4]
fmt.Printf("len: %d, cap: %d, data:%+v \n",len(sliceFromArr), cap(sliceFromArr), sliceFromArr)
//len: 2, cap: 4, data:[11 2]
//修改slice同时会修改array,因为slice中有array的指针
sliceFromArr = append(sliceFromArr, 33, 44)
fmt.Println(testArr) //[0 11 2 33 44]
fmt.Printf("len: %d, cap:%d, data:%+v \n", len(sliceFromArr), cap(sliceFromArr), sliceFromArr)
//len: 4, cap:4, data:[11 2 33 44]
//当len小于透视的数组的length时,对slice的修改都会同时修改它透视的数组
sliceFromArr = append(sliceFromArr, 55)
fmt.Println(testArr) //[0 11 2 33 44]
fmt.Printf("len: %d, cap: %d, data:%+v \n", len(sliceFromArr), cap(sliceFromArr), sliceFromArr)
//len: 5, cap: 8, data:[11 2 33 44 55]
//append()当len大于cap时,会重新开辟为原来slice的cap两倍的内存空间,并把slice拷贝到新开辟的空间中。
//所以原来的数组显示的依旧是原来的内存地址中的数据,而现在的slice已经存储来一个新开辟的8个int的空间中,
//对slice的修改不会改动原来的数组。
```
4. slice单独定义,并作为参数传递给函数:
```go
func setSlice(testSlice []int){
testSlice[0] = 10
testSlice[1] = 11
}
func setSliceByAppend(testSlice []int){
testSlice = append(testSlice, 22)
}
func setSliceByAppendPointer(testSlice *[]int){
*testSlice = append(*testSlice, 22)
}
func main(){
testSlice := make([]int, 2, 3)
testSlice[0] = 0
testSlice[1] = 1
fmt.Printf("len: %d, cap: %d, data:%+v \n", len(testSlice), cap(testSlice), testSlice)
//len: 2, cap: 3, data:[0 1]
setSlice(testSlice)
fmt.Printf("len: %d, cap: %d, data:%+v \n", len(testSlice), cap(testSlice), testSlice)
//len: 2, cap: 3, data:[10 11]
//因为slice中的array是指针类型所以在参数传递中,可以修改slice中array的值
setSliceByAppend(testSlice)
fmt.Printf("len: %d, cap: %d, data:%+v \n", len(testSlice), cap(testSlice), testSlice)
//len: 2, cap: 3, data:[10 11]
setSliceByAppendPointer(&testSlice)
fmt.Printf("len: %d, cap: %d, data:%+v \n", len(testSlice), cap(testSlice), testSlice)
//len: 3, cap: 3, data:[10 11 22]
//由setSliceByAppend和setSliceByAppendPointer的测试可以得知,
//使用append()来修改slice的值,会生成一个新的slice,新的slice内存地址和原来的就不一样了。
//如果需要使用append()来修改slice的值,需要使用指针类型的slice。
}
```
---
参考网址:
https://www.jb51.net/article/136199.htm
https://blog.golang.org/go-slices-usage-and-internals
http://www.cnblogs.com/hutusheng/p/5492418.html
有疑问加站长微信联系(非本文作者))