Go 切片

切片与数组相比,不需要设定长度,在[]中不用设定值,相对来说比较自由。

slice本身没有数据,是对底层array的一个view对slice所做的任何修改都将反映在底层数组中。

切片是什么?一种数据结构,类似数组,围绕动态数组的概念而设计,可按需自动改变大小

切片内部实现?切片基于数组实现,底层是数组(故底层的内存是连续分配,可根据索引获取数据,可迭代以及垃圾回收),自身非常(切片对象只有3个字段数据结构即:指向底层数组的指针ptr、切片长度len、切片容量cap),可看作对底层数组的抽象

切片如何声明?创建方式多样,比如make、或指定初始化值或基于现有切片(数组)创建

方法一简洁如make make([]T, length, capacity) ,比如 slice := make([]int,5) 指定切片长度为5, slice:=make([]int,5,10) 指定切片长度5,容量10(对应的是切片底层数组)

注:容量为10,但长度为5,故我们只能访问5个元素,剩下的5个元素需要切片扩充后才可访问。且容量>=长度。

方法二使用自变量:指定初始化值 slice := []int{1,2,3,4,5} 

方法三基于现有切片(数组)创建

基于两个索引 s := arr[startIndex:endIndex] //前闭后开 使用 [i:j] 操作符表示以i到j的左闭右开,类似Java的subString方法。

注:新切片和原切片共用一个底层数组,故当修改时候,底层数组的值会改变。

slice := []int{1,2,3,4,5}
newSlice := slice[1:3]
newSlice[0]=10
fmt.Println(slice) //输出是:[1 10 3 4 5] fmt.Println(newSlice) // [10 3]

基于三个索引 slice[i,j,k] //k为限定新切片容量<原切片最大索引值 

slice := []int{1,2,3,4,5}
newSlice := slice[1:2:3]
fmt.Printf("newSlice长度:%d,容量:%d",len(newSlice),len(newSlice)) //输出:长度为1  容量为1

切片初始值?切片底层为数组,创建切片不指定字面值,默认为数组元素的零值。类似数组,初始化可以为:

//数组初始化  array := [5]int{4:1}
slice := []int{4:1}

nil切片与空切片区别?长度、容量都为0.

nil切片(比如: var nilSlice []int )指向底层数组的指针为nil,nil切片表示不存在的切片。

空切片(比如: slice := []int{} )对应的指针是个地址,空切片表示一个空集合

基于原数组或切片创建一个新切片 新切片容量和大小是多少?

对底层数组容量是k的切片slice[i:j]而言,长度为: j-i ,容量为: k-i ,Go提供内置的 len 和 cap 来计算切片长度和容量。

slice := []int{1,2,3,4,5}
newSlice := slice[1:3]
fmt.Printf("newSlice长度:%d,容量:%d",len(newSlice),len(newSlice)) // 输出:长度2 容量2  3-1=2 5-3=2

如何使用切片?类似使用数组,通过索引获取切片对应元素的值,也可修改对应元素的值。

切片只能访问到长度内的元素,长度外的如果访问会运行时异常。

slice := []int{1,2,3,4,5}
fmt.Println(slice[2])  //3
slice[2] = 10 
fmt.Println(slice[2])  //10

切片如何按需增长?使用内置函数 append 可为一个切片追加一个元素

添加元素:s = append(s,val) 如果超越cap,系统会重新分配更大的底层数组。

append函数会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice。

但当slice中没有剩 余空间(即(cap-len) == 0)时,此时将动态分配新的数组空间。

返回的slice数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的slice则不受影响

slice := []int{1,2,3,4,5}
newSlice := slice[1:3]
newSlice = append(newSlice,10) 
fmt.Println(newSlice)   //[2 3 10]
fmt.Println(slice)      //[1 2 3 10 5]

append特点?智能增长底层数组的容量,当容量小于1000,成倍增长,容量超过1000,增长因子设为1.25,每次增加25%。

可变参:可同时追加好几个值

slice := []int{1,2,3,4,5}
newSlice := slice[1:2:3]
newSlice1 := slice[1:2]
fmt.Println(newSlice1)                       //[2]
newSlice = append(newSlice,slice ...)        
fmt.Println(newSlice)                        //[2 1 2 3 4 5]
fmt.Println(slice)                           //[1 2 3 4 5]

如何迭代切片? for range

slice := []int{1,2,3,4,5}
for _,v := range slice{
    fmt.Printf("值%d 
",v)   
}
for i:=0;i<len(slice);i++{
    fmt.Printf("value:%d
",slice[i])
}

函数间传递切片

func main() {
    slice := []int{1,2,3,4,5}
    fmt.Printf("%p 
",&slice)  
    modify(slice)
    fmt.Println(slice)
}
func modify(slice []int){
    fmt.Printf("%p
",&slice)
    slice[2] = 10
}
0xc420084020 
0xc420084040
[1 2 10 4 5]

 例子:

func main() {
    var numbers []int
    printSlice(numbers)

    /* 允许追加空切片 */
    numbers = append(numbers, 0)
    printSlice(numbers)

    /* 向切片添加一个元素 */
    numbers = append(numbers, 1)
    printSlice(numbers)

    /* 同时添加多个元素 */
    numbers = append(numbers, 2,3,4)
    printSlice(numbers)

    /* 创建切片 numbers1 是之前切片的两倍容量*/
    numbers1 := make([]int, len(numbers), (cap(numbers))*2)

    /* 拷贝 numbers 的内容到 numbers1 */
    copy(numbers1,numbers)
    printSlice(numbers1)
}

func printSlice(x []int){
    fmt.Printf("len=%d cap=%d slice=%v
",len(x),cap(x),x)
}

输出:

len=0 cap=0 slice=[]
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=6 slice=[0 1 2 3 4]
len=5 cap=12 slice=[0 1 2 3 4]
原文地址:https://www.cnblogs.com/ycx95/p/9383721.html