Slice切片

Slice切片

数组的缺点

  • 1. Go中的数组是值类型,换句话说,如果你将一个数组赋值给另外一个数组,那么,实际上就是将整个数组拷贝一份
  • 2. 如果Go中的数组作为函数的参数,那么实际传递的参数是一份数组的拷贝,而不是数组的指针。这个和C要区分开。因此,在Go中如果将数组作为函数的参数传递的话,那效率就肯定没有传递指针高了。

区分数组的声明和切片的声明方式

当使用字面量来声明切片时,其语法与使用字面量声明数组非常相似。二者的区别是:如果在 [] 运算符里指定了一个值,那么创建的就是数组而不是切片。只有在 [] 中不指定值的时候,创建的才是切片。看下面的例子

为什么需要切片

数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型Slices切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。切片中有两个概念:一是len长度,二是cap容量,长度是指已经被赋过值的最大下标+1,可通过内置函数len()获得。容量是指切片目前可容纳的最多元素个数,可通过内置函数cap()获得。切片是引用类型,因此在当传递切片时将引用同一指针,修改值将会影响其他的对象。

切片简介

  • 切片是可动态变化的序列,是对数组的引用,引用类型,遵循引用传递的机制
  • slice类型写作[]T,T是slice元素类型,var s1 []int,s1就是切片变量,空中括号是切片的典型标志

具体介绍

切片之所以被称为切片,是因为创建一个新的切片,也就是把底层数组切出一部分。通过切片创建新切片的语法如下:

其中 i 表示从 slice 的第几个元素开始切,j 控制切片的长度(j-i),k 控制切片的容量(k-i),如果没有给定 k,则表示切到底层数组的最尾部。
slice[i:j]
slice[i:j:k]

下面是几种常见的简写形式:

    // 创建一个整型切片 其长度和容量都是 5 个元素
    //对应的下标  0:10,1:20,2:30,3:40,4:50,
    myNum := []int{10, 20, 30, 40, 50}
    newNumTmp := myNum[1:4]
    //i 表示从 slice 下标为 i 开始切,j 控制切片的长度 
    //[i:j] 表示  从下标为i开始切,新的切片元素个数是  j-i 个
    //[:j] == [0:j] 
    //[i:] == [i:len()]
    //标识从下标1开始切    切  4-1 个元素  所以结果是 [20 30 40]
    newNumTmp1 := myNum[3:4]
    // 表示从 slice 下标为 3 的元素开始  切 4-3 等于1个元素  所以结果是  [40]
    newNumTmp2 := myNum[3:5]
    // 表示从 slice 下标为 3 的元素开始  切 5-3 等于2个元素  所以结果是  [40 50]
    newNumTmp3 := myNum[0:4]
    // 表示从 slice 下标为 0 的元素开始  切 4-0 等于4个元素  所以结果是  [10 20 30 40]
    newNumTmp4 := myNum[:4]
    // 表示从 slice 下标为 0 的元素开始  切 4-0 等于4个元素  所以结果是  [10 20 30 40]
    newNumTmp5 := myNum[2:]
    // 表示从 slice 下标为 2 的元素开始  切 切片的长度 - 2 等于5 - 2 等于 3 个元素  所以结果是  [30 40 50]
    newNumTmp6 := myNum[2:5]
    // 表示从 slice 下标为 2 的元素开始  切 切片的长度 - 2 等于5 - 2 等于 3 个元素  所以结果是  [30 40 50]

简单案例

//创建一个数组
var array1 [5]int = [...]int{11, 22, 33, 44, 55}
/*
创建切片,通过对数组的索引切片
s1 是切片名
array1[1:3]代表slice引用数组区间,索引1到索引3的值,注意取头不取尾,
*/
s1 := array1[1:4]
fmt.Printf("array1 = %v s1 = %v len(s1) = %v cap(s1) = %v \n",array1,s1,len(s1),cap(s1))

//结果
array1 = [11 22 33 44 55] s1 = [22 33 44] len(s1) = 3 cap(s1) = 4 

切片原理

  • slice是一个轻量级数据结构,提供访问数组子序列元素的功能。
  • slice由三个部分构成,指针、长度、容量
  • 指针:指针指向slice第一个元素对应的数组元素的地址。
  • 长度:slice元素的数量,不得超过容量。
  • 容器:slice开始的位置到底层数据的结尾。

切片操作

//创建数组data
array := [...]int{0, 1, 2, 3, 4, 5}
//切片s [2,3]
slice := array[2:4]
//切片读写操作目标是底层数组data,data的值会一起被修改
slice[0] += 100
slice[1] += 200
fmt.Printf("slice = %v array = %v",slice,array)
//运行结果
slice = [102 203] array = [0 1 102 203 4 5]

创建切片的方式

  • 1.定义切片,然后引用已经创建好的数组,数组可见
//创建数组和切片的不同,数组中,中括号不能为空,必须是 ...  或者是具体数字(元素个数)
var s1 []int = []int{1, 2, 3, 4, 5}
var array1 = [...]int{11, 22, 33, 44}
fmt.Printf("array1 = %v s1 = %v 长度 = %v 容量 = %v \n",array1,s1,len(s1),cap(s1))
//返回值
array1 = [11 22 33 44] s1 = [1 2 3 4 5] 长度 = 5 容量 = 5 

使用下标创建切片

// 使用空字符串初始化第 10 个元素
myStr := []string{9: ""}
fmt.Println(len(myStr))
fmt.Println(helper.InterfaceHelperObject.ToString(myStr))
//打印的结果如下
10
["","","","","","","","","",""]

创建空切片

var myNum []int
fmt.Println(myNum)
fmt.Println(nil)
fmt.Println(helper.InterfaceHelperObject.ToString(myNum))
//返回数据
[]
<nil>
null
  • 2.内置make函数创建切片,底层数组看不见,只能通过slice访问元素
内置make函数,参数(类型,len,cap),注意cap大于len,容量可以省略,默认等于长度
//如果cap不传默认容量就是长度
slice3 := make([]int, 10) 和 slice := make([]int, 10, 10) 一个意思

//简单案例
slice := make([]int, 10, 30)
slice[0] = 11
//如果 slice[10] = 11 或者 slice[11] = 11 都会报错,因为 下标范围是 0 - 9 
//也就是下边必须小于 10 ,30代表 append 的时候最多到下边 29
//     slice = append(slice, 400)
fmt.Printf("slice = %v",slice)
//打印
slice = [11 0 0 0 0 0 0 0 0 0]
本作品采用《CC 协议》,转载必须注明作者和本文链接
good good study day day up
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!