目录
1.初识切片
/*
概念:
切片是一组长度不固定的相同类型数据集合;切片是不存储数据的,是靠底层的数组存储数据;
声明格式:
var 切片名称 []数据类型
注意:
1.切片不能存储的数据不能超过切片长度
2.var 切片名称 []数据类型 声明的未赋值时等于nil,make创建的未赋值时不等于nil
*/
func main() {
//1.普通方式
var s1 []int // 或者定义时直接初始化 var s1 = []int {1, 2, 3, 4, 5}
fmt.Println(len(s1), cap(s1)) // 0 0
if s1 == nil {
fmt.Println("切片为空") //切片为空
}
s1 = []int{1, 2, 3, 4, 5}
fmt.Println(len(s1), cap(s1)) // 5 5
fmt.Printf("s1:%d,数据类型:%T\n", s1, s1) //s1:[1 2 3 4 5],数据类型:[]int
//2.简化方式
s2 := []int{6, 6, 6, 8, 8, 8}
fmt.Printf("s2:%d,数据类型:%T\n", s2, s2) //s2:[6 6 6 8 8 8],数据类型:[]int
//3.make方式 make([]T,len,cap) 切片类型,切片长度,切片容量
s3 := make([]string, 3, 5)
if s3 == nil { //s3不等于nil,不会进来
fmt.Println("切片为空")
}
fmt.Println(s3)
s3 = []string{"张三", "李四", "王五"}
fmt.Println(s3)
//s3[3] = "赵六" // panic: runtime error: index out of range [3] with length 3
}
2.切片遍历
func main() {
slice := []string{"张三", "李四", "王五"}
//1.fori方式
for i := 0; i < len(slice); i++ {
fmt.Printf("i=%d,v=%s\n", i, slice[i])
}
fmt.Println("=================")
//2.for方式
for i := range slice {
fmt.Printf("i=%d,v=%s\n", i, slice[i])
}
//3.forr方式
fmt.Println("=================")
for i, v := range slice {
fmt.Printf("i=%d,v=%s\n", i, v)
}
}
3.切片扩容
append(切片,数据列表)
func main() {
slice := make([]int, 0, 5)
// slice[0] = 3 赋值不能超过切片长度,会报索引越界
//1.普通扩容
slice = append(slice, 1, 2)
fmt.Println(slice)
//2.解构切片扩容...
slice2 := []int{3, 4, 5}
slice = append(slice, slice2...)
fmt.Println(slice)
}
4.切片扩容原理
/*
切片扩容后:
长度变为扩容后的长度;长度如果没超过当前容量,容量不变,内存地址也不变;
如果切片长度超过当前容量,且切片长度小于1024:容量×2,内存地址发生改变;
如果切片长度超过当前容量,且切片长度大于1024:容量×1.25,内存地址发生改变;
*/
func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Printf("len:%d,cap:%d,addr:%p\n", len(slice), cap(slice), slice) //len:5,cap:5,addr:0xc00000e360
slice = append(slice, 6, 7)
fmt.Printf("len:%d,cap:%d,addr:%p\n", len(slice), cap(slice), slice) //len:7,cap:10,addr:0xc00001a1e0
slice = append(slice, 8, 9)
fmt.Printf("len:%d,cap:%d,addr:%p\n", len(slice), cap(slice), slice) //len:9,cap:10,addr:0xc00001a1e0
slice = append(slice, 10, 11, 12)
fmt.Printf("len:%d,cap:%d,addr:%p\n", len(slice), cap(slice), slice) //len:12,cap:20,addr:0xc0000220a0
}
5.通过截取数组创建切片
/*
slice := arr[start:end] 包头不包尾
长度=切片的数据数量
容量=数组长度-start
*/
func main() {
arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println(arr)
s1 := arr[0:5]
fmt.Printf("s1:%v,数据类型:%T,len:%d,cap:%d\n", s1, s1, len(s1), cap(s1))//s1:[1 2 3 4 5],数据类型:[]int,len:5,cap:10
s2 := arr[3:8]
fmt.Printf("s2:%v,数据类型:%T,len:%d,cap:%d\n", s2, s2, len(s2), cap(s2))//s2:[4 5 6 7 8],数据类型:[]int,len:5,cap:7
s3 := arr[5:]
fmt.Printf("s3:%v,数据类型:%T,len:%d,cap:%d\n", s3, s3, len(s3), cap(s3))//s3:[6 7 8 9 10],数据类型:[]int,len:5,cap:5
s4 := arr[:]
fmt.Printf("s4:%v,数据类型:%T,len:%d,cap:%d\n", s4, s4, len(s4), cap(s4))//s4:[1 2 3 4 5 6 7 8 9 10],数据类型:[]int,len:10,cap:10
}
6.引用传递
/*
引用传递:变量赋值,新的变量会指向原有变量的内存地址,新旧切片修改会相互影响
*/
func main() {
s1 := []int{1, 2, 3, 4, 5}
s2 := s1
fmt.Println("s1", s1) //s1 [1 2 3 4 5]
fmt.Println("s2", s2) //s2 [1 2 3 4 5]
fmt.Println("===========")
s2[0] = 100
fmt.Println("s1", s1) //s1 [100 2 3 4 5]
fmt.Println("s2", s2) //s2 [100 2 3 4 5]
}
7.浅拷贝和深拷贝
浅拷贝:拷贝的是数据的地址;引用类型都是浅拷贝
深拷贝:拷贝的是数据本身;值类型的数据都是深拷贝
/*
切片是浅拷贝,在6中有实现;
切片通过copy方法实现深拷贝:copy(目标对象,源对象)
*/
func main() {
s1 := []int{1, 2, 3, 4}
s2 := make([]int, 4, 4)
fmt.Println(s1, s2) //[1 2 3 4] [0 0 0 0]
copy(s2, s1)
fmt.Println(s1, s2) //[1 2 3 4] [1 2 3 4]
s1[0] = 10
fmt.Println(s1, s2) //[10 2 3 4] [1 2 3 4],通过copy实现了切片的深拷贝
}