切片
切片的定义
切片是对数组的抽象,提供了更强大和灵活的数据结构。切片本身不存储任何数据,而是引用一个底层数组的一部分。
语法格式:
go
// 切片的[]是不能有长度的。
var 变量名 []数据类型
go
// 使用make内置函数创建切片
// 数据类型: Slice、Map、Channel
// 长度: 当前包含的元素个数
// 容量: 当前底层容纳的最大元素个数
make([]数据类型, 长度, 容量)
// 另一种写法
var 变量名 []数据类型 = make([]数据类型, 长度, 容量)
// 也可以简写
变量名 := make([]数据类型, 长度, 容量)
示例:
go
package main
import "fmt"
func main() {
// 定义一个int类型的切片
var s1 []int
fmt.Printf("s1的类型:%T\n", s1)
// 使用make函数定义一个string类型的切片
s2 := make([]string, 0, 3)
fmt.Printf("s2的类型:%T\n", s2)
}
go
package main
import "fmt"
func main() {
// 定义string类型切片
// 此时的切片为空【栈内存已经分配好切片的指针、长度、容量】
// 但是堆内存中还没有给切片分配任何存储空间
var s1 []string // nil
// 定义int类型切片
// 这里原理同上【和s1切片同理】
var s2 []int // nil
// 定义一个int类型空切片
s3 := []int{} // {}
// 打印三个切片
fmt.Println(s1, s2, s3) // [] [] []
// 打印三个切片的长度
fmt.Println(len(s1), len(s2), len(s3)) // 0 0 0
// 切片判断为空
fmt.Println(s1 == nil) // true
fmt.Println(s2 == nil) // true
fmt.Println(s3 == nil) // false
}
go
package main
import "fmt"
func main() {
// make函数创建string类型切片
// 使用 make 创建的切片都不可能是 nil
s1 := make([]string, 0)
fmt.Println(len(s1)) // 0
// 判断make函数创建的切片是否为nil
fmt.Println(s1 == nil)
}
给切片添加元素
使用 append()
函数是用来向切片末尾追加元素。
语法格式:
go
append(切片, 元素1, 元素2, 元素3, ..., 元素n)
示例:
go
package main
import "fmt"
func main() {
// 使用make函数定义一个int类型切片,切片的长度为0,容量为5
// 此时这个切片是空的,但是这个切片不是nil,空不等同于nil,不等同于nil
// 空是说明容器是没有东西的,nil是这个容器不存在的
s1 := make([]int, 0, 5)
fmt.Println(s1) // 此时的切片是[]
// 使用append函数向切片中添加元素
s1 = append(s1, 1, 2, 3, 4)
fmt.Println(s1) // [1 2 3 4]
}
go
package main
import "fmt"
func main() {
// 使用append函数给切片末尾追加元素。
// append函数只能在末尾追加元素,不能在中间【或者指定索引位置】插入元素。
// 注意append函数会返回一个新切片,所以这里需要重新赋值给s1
s1 := make([]int, 5, 10) // 这里初始化的切片前面5个元素是0,后面5个元素是nil
fmt.Printf("s1类型:%T\n", s1)
fmt.Printf("s1长度:%d,s1容量:%d\n", len(s1), cap(s1)) // len: 5, cap: 10
fmt.Printf("s1:%v\n", s1)
fmt.Println("=======================")
fmt.Println("append()第一次")
s1 = append(s1, 1, 2, 3, 4, 5) // 5个元素
fmt.Printf("s1类型:%T\n", s1)
fmt.Printf("s1长度:%d,s1容量:%d\n", len(s1), cap(s1))
fmt.Printf("s1:%v\n", s1)
fmt.Println("=======================")
fmt.Println("append()第二次") // 第二次追加元素,发现容量不够,自动扩容
s1 = append(s1, 6, 7, 8) // 3个元素
fmt.Printf("s1类型:%T\n", s1)
fmt.Printf("s1长度:%d,s1容量:%d\n", len(s1), cap(s1)) // len: 13, cap: 20
fmt.Printf("s1:%v\n", s1)
}
将数组转成切片
语法格式:
go
// 索引是左闭右开的【包含起始索引的元素直到结束索引的前一个元素,但不包含结束索引的元素】
// 所以切片的长度是结束索引减去起始索引。
var 变量名 = 数组[起始索引:结束索引]
示例:
go
package main
import "fmt"
func main() {
// 将数组转成切片语法格式:数组名[起始索引:结束索引]
// 定义一个int类型长度10的数组
arr1 := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 打印数组信息
fmt.Printf("len:%d\n", len(arr1)) // len:10
fmt.Printf("arr1:%T\n", arr1) // arr1:[10]int
// 将数组索引为2到5的元素转成切片
// 这里2到5是左闭右开的等价于[2,5)表示一个开区间,其中包含2但不包含5
// 长度等于结束索引减去起始索引,所以长度为3
s1 := arr1[2:5]
fmt.Printf("len:%d\n", len(s1)) // len:3
fmt.Printf("s1:%T\n", s1) // s1:[]int
}
go
package main
import "fmt"
func main() {
// 将数组转成切片语法格式:数组名[起始索引:结束索引]
// 创建一个int类型长度10的数组
arr1 := [10]int{27, 86, 82, 48, 80, 83, 19, 68, 96, 79}
fmt.Printf("arr1的类型:%T\n", arr1)
fmt.Printf("arr1的长度:%d,容量:%d\n", len(arr1), cap(arr1))
fmt.Printf("arr1的内容:%v\n", arr1)
fmt.Println("=======================================")
// 将数组转成切片,这里的[:]表示将数组的全部元素拷贝到切片中
s1 := arr1[:]
fmt.Printf("s1的类型:%T\n", s1)
fmt.Printf("s1的长度:%d,容量:%d\n", len(s1), cap(s1))
fmt.Printf("s1的内容:%v\n", s1)
fmt.Println("=======================================")
// 从:左边没有写就是从0开始拷贝元素,直到拷贝到:右边的索引为4位置,索引为5是不包含的.
s2 := arr1[:5]
fmt.Printf("s2的类型:%T\n", s2)
fmt.Printf("s2的长度:%d,容量:%d\n", len(s2), cap(s2))
fmt.Printf("s2的内容:%v\n", s2)
fmt.Println("=======================================")
// 从:右边没有写就是从索引为6位置开始拷贝元素,直到拷贝到数组的最后一个元素.
s3 := arr1[6:]
fmt.Printf("s3的类型:%T\n", s3)
fmt.Printf("s3的长度:%d,容量:%d\n", len(s3), cap(s3))
fmt.Printf("s3的内容:%v\n", s3)
}
切片拷贝
使用 copy()
函数可以将一个数组切片的元素拷贝到另一个数组切片中。
语法格式:
go
copy(目标切片, 源切片) // 返回拷贝的元素个数
示例:
go
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{6, 7, 8}
// 拷贝之前
fmt.Printf("s1:%v\n", s1) // [1 2 3 4 5]
fmt.Printf("s1的长度:%d,s1的容量:%d\n", len(s1), cap(s1))
fmt.Printf("s2:%v\n", s2) // [6 7 8]
fmt.Printf("s2的长度:%d,s2的容量:%d\n", len(s2), cap(s2))
// 将s1拷贝到s2
copy(s2, s1)
fmt.Printf("s1:%v\n", s1) // [1 2 3 4 5]
fmt.Printf("s1的长度:%d,s1的容量:%d\n", len(s1), cap(s1))
fmt.Printf("s2:%v\n", s2) // [1 2 3]
fmt.Printf("s2的长度:%d,s2的容量:%d\n", len(s2), cap(s2))
}
go
package main
import "fmt"
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{6, 7, 8}
// 拷贝之前
fmt.Printf("s1:%v\n", s1) // [1 2 3 4 5]
fmt.Printf("s1的长度:%d,s1的容量:%d\n", len(s1), cap(s1))
fmt.Printf("s2:%v\n", s2) // [6 7 8]
fmt.Printf("s2的长度:%d,s2的容量:%d\n", len(s2), cap(s2))
// 将s2拷贝到s1
copy(s1, s2)
// 拷贝之后
fmt.Printf("s1:%v\n", s1) // [6 7 8 4 5]
fmt.Printf("s1的长度:%d,s1的容量:%d\n", len(s1), cap(s1))
fmt.Printf("s2:%v\n", s2) // [6 7 8]
fmt.Printf("s2的长度:%d,s2的容量:%d\n", len(s2), cap(s2))
}
切片中移除元素
在 Go 语言中切片并没有删除元素的方法或者是接口,需要根据切片本身的特性,来删除切片中的元素。
首先介绍的是从开头位置移除[删除]切片中的元素。
示例:
go
package main
import "fmt"
func main() {
// 直接移动数据指针的方式删除切片中的元素
// 删除开头N个元素语法格式:切片名 = 切片名[N:]
// 定义切片初始化5个元素
s1 := []int{1, 2, 3, 4, 5}
fmt.Println(s1) // [1 2 3 4 5]
s1 = s1[1:] // 删除第一个元素【从下标1开始截取到末尾】
fmt.Println(s1) // [2 3 4 5]
}
go
package main
import "fmt"
func main() {
// 定义切片
s1 := []int{1, 2, 3, 4, 5}
fmt.Println(s1) // [1 2 3 4 5]
// 通过 append 函数将第一个元素之后的所有元素复制到一个新的切片中,覆盖原切片内容。
s1 = append(s1[:0], s1[1:]...)
fmt.Println(s1) // [2 3 4 5]
}
从中间位置移除[删除]切片中的元素。
示例:
go
package main
import "fmt"
func main() {
// 定义一个切片int类型
s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
fmt.Println(s1)
// 移除值为10的元素
s1 = append(s1[:9], s1[10:]...)
fmt.Println(s1)
}
从尾部位置移除[删除]切片中的元素。
示例:
go
package main
import "fmt"
func main() {
// 定义切片
s1 := []int{1, 2, 3, 4, 5}
fmt.Println(s1)
// 移除后面一个元素
s1 = s1[:len(s1)-1]
fmt.Println(s1)
// 移除后面N个元素
s1 = s1[:len(s1)-2]
fmt.Println(s1)
}
多维切片(了解)
多维切片与多维数组类似,但是多维切片的元素是切片,而不是数组。
语法格式:
go
var 多维切片名 [][]...[] 数据类型
示例:
go
package main
import "fmt"
func main() {
// 定义一个二维切片
twoDimSlice := make([][]int, 3)
// 为每个一维切片分配内存空间
for i := range twoDimSlice {
twoDimSlice[i] = make([]int, 4)
}
// 填充数据
twoDimSlice[0] = []int{1, 2, 3, 4}
twoDimSlice[1] = []int{5, 6, 7, 8}
twoDimSlice[2] = []int{9, 10, 11, 12}
// 访问元素
fmt.Println(twoDimSlice[1][2]) // 输出: 7
}
go
package main
import "fmt"
func main() {
// 定义一个三维切片
threeDimSlice := make([][][]int, 2)
// 为每个二维切片分配内存空间
for i := range threeDimSlice {
threeDimSlice[i] = make([][]int, 3)
for j := range threeDimSlice[i] {
threeDimSlice[i][j] = make([]int, 4)
}
}
// 填充数据
threeDimSlice[0][0] = []int{1, 2, 3, 4}
threeDimSlice[0][1] = []int{5, 6, 7, 8}
threeDimSlice[0][2] = []int{9, 10, 11, 12}
threeDimSlice[1][0] = []int{13, 14, 15, 16}
threeDimSlice[1][1] = []int{17, 18, 19, 20}
threeDimSlice[1][2] = []int{21, 22, 23, 24}
// 访问元素
fmt.Println(threeDimSlice[1][1][2]) // 输出: 19
}