1.无论是C语言中的数组还是Go语言中的数组,数组的长度一旦确定就不能改变, 但在实际开发中我们可能事先不能确定数组的长度, 为了解决这类问题Go语言中推出了一种新的数据类型切片
2.什么是切片?
切片简单理解就是一个可变长度的数组
底层的实现原理就是一个结构体, 结构体中有一个指针指向了一个数组
本质上所有的数据都是保存在指向的数组中的
type slice struct{
array unsafe.Pointer // 指向底层数组指针
len int // 切片长度(保存了多少个元素)
cap int // 切片容量(可以保存多少个元素)
}
3.如何创建切片
1.通过数组来创建切片
3.1通过数组来创建格式: [起始位置:结束位置], 从起始位置开始截取, 直到结束位置, 但是不包括结束位置注意: 截取了多少个元素, len就等于几容量等于数组的长度 - 起始位置 var ages [5]int = [5]int{1, 3, 5, 7, 9}
// 2.通过数组创建切片
// [起始位置:结束位置], 从起始位置开始截取, 直到结束位置, 但是不包括结束位置
//var sce []int = ages[0:2]
//var sce []int = ages[2:4]
// 注意点: 如果只写了起始位置, 没有写结束位置, 那么会截取到最后
//var sce []int = ages[0:]
//var sce []int = ages[2:]
// 注意点: 如果只写了结束位置, 没有写开始位置, 那么会从开始截取到指定的结束位置
//var sce []int = ages[:2]
// 注意点: 如果只写了:, 那么就是从开始截取到末尾
var sce []int = ages[:]
fmt.Println(sce)
// 计算切片当前保存数据的个数
fmt.Println(len(sce))
// 计算切片总共可以保存数据的个数
fmt.Println(cap(sce))2.通过make函数来创建切片
// 第一个参数: 告诉系统要存储什么类型的数据
// 注意点: 如果是创建切片一定要在传入的数据类型前面写上[]
// 第二个参数: 告诉系统创建出来的切片len等于多少
// 第三个参数: 告诉系统创建出来的切片cap等于多少
// 注意点: 第三个参数可以省略, 如果省略切片的容量就等于切片的长度(等于第二个参数)
//var sce []int = make([]int, 2, 5)
var sce []int = make([]int, 2)
fmt.Println(sce)
fmt.Println(len(sce))
fmt.Println(cap(sce))3.通过语法糖来创建切片
// 一定要注意[]里面没有值就是切片
// 通过Go提供的语法糖来创建len等于cap
var sce []int = []int{1, 3, 5} // 相当于make([]int, 3)
fmt.Println(sce)
fmt.Println(len(sce))
fmt.Println(cap(sce))
append函数
1.容量
如果通过append函数追加数据之后超过了原有的容量, 那么系统内部会自动按照当前容量*2的方式重新定义一个数组作为切片保存数据的模型注意点:
容量小于1024的时候扩容, 会按照原有容量的2倍扩容
容量大于1024的时候扩容, 会按照原有容量1/4倍扩容
2.为什么append函数要返回一个切片
因为在扩容的时候会重新定义一个新的切片, 所以需要返回一个切片var sce []int = make([]int, 2, 5)
sce = append(sce, 6)
fmt.Printf("%p\n", sce)
fmt.Println(sce)
fmt.Println(cap(sce))
切片的使用
删除切片中的值var sce []int = {1,3,5,7,9}
index := 2
sce = Append(sce[:index],sce[index+1:]...)
规律:
将第二次截取的切片添加到第一次截取的截屏后面即可
// 通过切片生成切片的注意点
// 1.创建一个数组 var
arr [5]int = [5]int{1, 3, 5, 7, 9} // 数组
// Go语言中不能直接通过数组名获取数组的地址
//fmt.Printf("%p\n", arr)
fmt.Printf("%p\n", &arr)
fmt.Printf("%p\n", &arr[0])
// 2.通过数组创建一个切片
var sce []int = arr[:]
// 直接打印sce打印的是sce中指针保存的地址
// 也就是底层指向的那个数组的地址
fmt.Printf("%p\n", sce)
// 3.通过切片创建一个切片
// 通过切片创建一个切片, 新的切片和老的切片底层指向同一个数组
var sce2 []int = sce[:] fmt.Printf("%p\n", sce2)
// 4.直接修改数组的值
//arr[1] = 666
//sce[1] = 666
sce2[1] = 666
fmt.Println(arr)
fmt.Println(sce)
fmt.Println(sce2)copy的使用
sce1 := []int{1, 3} // 源切片
sce2 := []int{0, 0, 0} // 目标切片
fmt.Println(sce2)
// 第一个参数:目标切片
// 第二个参数:源切片
// 会将源切片中的数据拷贝到目标切片中
// 拷贝的时候会以目标切片为主
copy(sce2, sce1)
fmt.Println(sce2)//{1,3,0}
通过copy改变字符串中的字符
var str string = "www.it666.com"
sce := make([]byte, len(str))
copy(sce, str)
sce[0] ='M'
fmt.Printf("%s\n", sce)