Go学习(十): 切片

1.切片的概念

Go语言中数组的长度不可改变,但在很多应用场景中,在初始定义数组时,数组的长度并不可预知,这样的序列集合无法满足要求。Go中提供了另外一种内置类型切片(slice),弥补了数组的缺陷。从底层来看,切片引用了数组的对象。切片可以追加元素,在追加时可能使切片的容量增大。与数组相比,切片不需要设定长度,在[]中不用设定值,相对来说比较自由。

2.切片声明使用

2.1 通过make

//使用make()函数来创建切片
var slice1 = make([]int,3)
slice1[0] = 1
slice1[1] = 2
slice1[2] = 4
fmt.Printf("通过make关键字[slic1] 类型:%T 值:%v \n",slice1,slice1)
//  输出: 通过make关键字[slic1] 类型:[]int 值:[1 2 4] 

2.2 直接初始化

// 直接初始化使用
slice2 := []int{1,2,4}
fmt.Printf("直接初始化使用[slic2] 类型:%T 值:%v \n",slice2,slice2)
// 输出: 直接初始化使用[slic2] 类型:[]int 值:[1 2 4] 

2.3 通过数组截取

package main
import "fmt"
func main() {
    // 定义一个数组
    arr := [...]int{1,2,4,6,8,10,12,14,16}
    // 从索引0开始截取到索引为4(不包括4)
    slice3 := arr[0:4]
    fmt.Printf("从索引0开始截取到索引为4(不包括4)[slice3] 类型:%T 值:%v \n",slice3,slice3)
    // 索引从0开始时,0也可以省略不写
    slice33 := arr[:4]
    fmt.Printf("从索引0开始截取到索引为4(不包括4)[slice33] 类型:%T 值:%v \n",slice33,slice33)
    // 从索引4开始截取到最后
    slice4 := arr[5:]
    fmt.Printf("从索引5开始截取到最后[slice4] 类型:%T 值:%v \n",slice4,slice4)
}
/**输出
从索引0开始截取到索引为4(不包括4)[slice3] 类型:[]int 值:[1 2 4 6] 
从索引0开始截取到索引为4(不包括4)[slice33] 类型:[]int 值:[1 2 4 6] 
从索引5开始截取到最后[slice4] 类型:[]int 值:[10 12 14 16] 
*/

3.切片删除

3.1 删除第一个元素

package main
import "fmt"
func main()  {
    // 定义一个切片
    slice := []int{1,2,3,4,5,6}
    fmt.Printf("切片slice--> 值:%v len: %d cap: %d\n",slice,len(slice),cap(slice))
    // 删除第一个元素
    slice = slice[1:]
    fmt.Printf("删除一个元素后--> 值:%v len: %d cap: %d\n",slice,len(slice),cap(slice))
}
/*输出
切片slice--> 值:[1 2 3 4 5 6] len: 6 cap: 6
删除一个元素后--> 值:[2 3 4 5 6] len: 5 cap: 5
*/

3.2 删除最后一个元素

package main
import "fmt"
func main()  {
    // 定义一个切片
    slice := []int{1,2,3,4,5,6}
    fmt.Printf("切片slice--> 值:%v len: %d cap: %d\n",slice,len(slice),cap(slice))
    // 删除最后一个元素
    slice = slice[:len(slice)-1]
    fmt.Printf("删除一个元素后--> 值:%v len: %d cap: %d\n",slice,len(slice),cap(slice))
}
/*输出
切片slice--> 值:[1 2 3 4 5 6] len: 6 cap: 6
删除一个元素后--> 值:[1 2 3 4 5] len: 5 cap: 6
*/

3.3 删除指定位置元素

package main
import "fmt"
func main()  {
    // 定义一个切片
    slice := []int{1,2,3,4}
    fmt.Printf("切片slice--> 值:%v len: %d cap: %d\n",slice,len(slice),cap(slice))
    index := 2
    // 指定索引前面一部分
    front := slice[:index]
    // 指定索引后面一部分
    behind := slice[index+1:]
    // 拼起来
    slice =  append(front,behind...)
    fmt.Printf("删除索引%d后--> 值:%v len: %d cap: %d\n",index,slice,len(slice),cap(slice))
}

4.len()和cap()

4.1 作用

切片的长度是切片中元素的数量。切片的容量是从创建切片的索引开始的底层数组中元素的数量。切片可以通过len()方法获取长度,可以通过cap()方法获取容量。数组计算cap()结果与len()相同

4.2 使用

package main
import "fmt"
func main() {
    // 创建一个切片
    slice := []int{1,2,4,6,8,10,12,14,16}
    fmt.Printf("切片slice, len:%d cap:%d \n",len(slice),cap(slice))
    
    // 清空切片slice赋值给slice1
    slice1 := slice[0:0]
    fmt.Printf("切片slice1, len:%d cap:%d \n",len(slice1),cap(slice1))

    // 使用make指定容量创建切片
    var slice2 = make([]int,4,8)
    slice2[1] = 1
    slice2[3] = 3
    fmt.Printf("切片slice2, len:%d cap:%d \n",len(slice2),cap(slice2))

    // 数组计算cap()结果与len()相同
    arr := [...]int{1,2,4,6,8,10,12,14,16}
    fmt.Printf("数组arr, len:%d cap:%d \n",len(arr),cap(arr))
}
/***输出:
切片slice, len:9 cap:9 
切片slice1, len:0 cap:9 
切片slice2, len:4 cap:8 
数组arr, len:9 cap:9 
*/

5.切片是引用类型

切片没有自己的任何数据。它只是底层数组的一个引用。对切片所做的任何修改都将反映在底层数组中。数组是值类型,而切片是引用类型。

5.1 函数传参

package main
import "fmt"
func testSlice(slice []int)  {
    // 修改切片的值
    slice[0] = 100
}
func main() {
    // 创建一个切片
    var slice = make([]int,4,4)
     slice = []int{1,2,3,4}
     fmt.Printf("变量slice  类型: %T 内存地址: %p 值:%v \n",slice,&slice,slice)
     // 调用函数修改
     testSlice(slice)
     fmt.Printf("调用函数后,变量slice  类型: %T 内存地址: %p 值:%v \n",slice,&slice,slice)
}
/**输出
变量slice  类型: []int 内存地址: 0xc00000c080 值:[1 2 3 4] 
调用函数后,变量slice  类型: []int 内存地址: 0xc00000c080 值:[100 2 3 4] 
*/

5.2 多切片共享

修改切片数值,当多个切片共享相同的底层数组时,对每个元素所做的更改将在数组中反映出来。

package main
import "fmt"
func testSlice(slice []int) {
    // 修改切片的值
    slice[0] = 100
}
func main() {
    // 创建一个切片
    var slice = make([]int, 4, 4)
    slice = []int{1, 2, 3, 4}
    fmt.Printf("变量slice  类型: %T 内存地址: %p 值:%v \n", slice, &slice, slice)
    // 复制给另外一个切片
    sliceCopy := slice
    fmt.Printf("变量sliceCopy  类型: %T 内存地址: %p 值:%v \n", sliceCopy, &sliceCopy, sliceCopy)
    // 从切片中截取
    slice2 := slice[0:2]
    fmt.Printf("变量slice2  类型: %T 内存地址: %p 值:%v \n", slice2, &slice2, slice2)
    // 调用函数修改
    testSlice(slice)
    fmt.Printf("调用函数后---变量slice  类型: %T 内存地址: %p 值:%v \n", slice, &slice, slice)
    fmt.Printf("调用函数后---变量sliceCopy  类型: %T 内存地址: %p 值:%v \n", sliceCopy, &sliceCopy, sliceCopy)
    fmt.Printf("调用函数后---变量slice2  类型: %T 内存地址: %p 值:%v \n", slice2, &slice2, slice2)
}

6.append()和copy()

6.1 作用

  • append():用于往切片中追加新元素,可以向切片里面追加一个或者多个元素,也可以追加一个切片。
  • copy(): 不会建立源切片与目标切片之间的联系。也就是两个切片不存在联系,其中一个修改不影响另一个。

6.2 使用append()

package main
import "fmt"
func testSlice(slice []int) {
    // 修改切片的值
    slice[0] = 100
}
func main() {
    // 定义一个切片类型,长度为0,容量为4
    var slice = make([]int, 0, 4)

    //向切片中添加1个元素 (不超过容量)
    slice1 := append(slice,1)
    fmt.Printf("变量slice1 --- 值: %v 长度(len):%d 容量(cap): %d  地址: %p \n",
        slice1,len(slice1),cap(slice1),&slice1 )

    // 向切片中添加多个元素(不超过容量)
    slice2 := append(slice,3,4,5)
    fmt.Printf("变量slice2 --- 值: %v 长度(len):%d 容量(cap): %d 地址: %p \n",
        slice2,len(slice2),cap(slice2),&slice2 )

    // 向切片中添加一个切片(超过容量)
    newSlice := []int{1,2,3,4,5,6,7}
    slice3 := append(slice,newSlice[:]...)
    fmt.Printf("变量slice3 --- 值: %v 长度(len):%d 容量(cap): %d 地址: %p \n",
        slice3,len(slice3),cap(slice3),&slice3 )

  // 调用函数修改
    testSlice(slice1)
    fmt.Printf("调用函数后-变量slice1 --- 值: %v 长度(len):%d 容量(cap): %d 地址: %p \n",
        slice1,len(slice1),cap(slice1),&slice1 )
    fmt.Printf("调用函数后-变量slice2 --- 值: %v 长度(len):%d 容量(cap): %d 地址: %p \n",
        slice2,len(slice2),cap(slice2),&slice2 )
    fmt.Printf("调用函数后-变量slice3 --- 值: %v 长度(len):%d 容量(cap): %d 地址: %p \n",
        slice3,len(slice3),cap(slice3),&slice3 )
}
/**输出
变量slice1 --- 值: [1] 长度(len):1 容量(cap): 4  地址: 0xc00000c080 
变量slice2 --- 值: [3 4 5] 长度(len):3 容量(cap): 4 地址: 0xc00000c0c0 
变量slice3 --- 值: [1 2 3 4 5 6 7] 长度(len):7 容量(cap): 8 地址: 0xc00000c100 
调用函数后-变量slice1 --- 值: [100] 长度(len):1 容量(cap): 4 地址: 0xc00000c080 
调用函数后-变量slice2 --- 值: [100 4 5] 长度(len):3 容量(cap): 4 地址: 0xc00000c0c0 
调用函数后-变量slice3 --- 值: [1 2 3 4 5 6 7] 长度(len):7 容量(cap): 8 地址: 0xc00000c100 
*/

append()会改变切片所引用的数组的内容,从而影响到引用同一数组的其他切片。当使用append()追加元素到切片时,如果容量不够(也就是(cap-len) == 0),Go就会创建一个新的内存地址来储存元素。

6.3 使用copy()

package main
import "fmt"
func main()  {
    // 定义一个切片
    slice := []int{1,2,3,4}
    fmt.Printf("变量slice --- 值: %v 长度(len):%d 容量(cap): %d  地址: %p \n",
        slice,len(slice),cap(slice),&slice )

    // 定义一个切片变量用来复制slice
    copySlice := make([]int,8)

    // 使用copy
    count := copy(copySlice,slice)
    fmt.Printf("复制的数量: %d \n",count)
    fmt.Printf("变量copySlice --- 值: %v 长度(len):%d 容量(cap): %d  地址: %p \n",
        copySlice,len(copySlice),cap(copySlice),©Slice )

    // 修改复制后的切片,源切片不会变
    copySlice[0] = 100
    fmt.Printf("修改后-->变量slice --- 值: %v 长度(len):%d 容量(cap): %d  地址: %p \n",
        slice,len(slice),cap(slice),&slice )
    fmt.Printf("修改后-->变量copySlice --- 值: %v 长度(len):%d 容量(cap): %d  地址: %p \n",
        copySlice,len(copySlice),cap(copySlice),©Slice )
}
/**输出
变量slice --- 值: [1 2 3 4] 长度(len):4 容量(cap): 4  地址: 0xc00000c080 
复制的数量: 4 
变量copySlice --- 值: [1 2 3 4 0 0 0 0] 长度(len):8 容量(cap): 8  地址: 0xc00000c0c0 
修改后-->变量slice --- 值: [1 2 3 4] 长度(len):4 容量(cap): 4  地址: 0xc00000c080 
修改后-->变量copySlice --- 值: [100 2 3 4 0 0 0 0] 长度(len):8 容量(cap): 8  地址: 0xc00000c0c0 
*/

微信搜索关注【猿码记】查看更多文章。

你可能感兴趣的:(go)