切片
什么是切片
- 切片长度不固定,不设定长度
- 内置数据类型
- 三元素:
- 指针 slice 指定的开始位置
- 长度 slice 的长度
- 容量 slice 开始到最后的最大长度
package main
import "fmt"
func main() {
/*
切片特点:
- 切片长度不固定,不设定长度
- 内置数据类型
- 三元素:
- 指针 slice 指定的开始位置
- 长度 slice 的长度
- 容量 slice 开始到最后的最大长度
*/
// 定义切片
slice01 := []int{} //
fmt.Printf("%T\n", slice01)
fmt.Println("默认切片:", slice01)
fmt.Println("切片长度:", len(slice01))
fmt.Println("切片容量:", cap(slice01))
// 定义空切片 slice02 == nil
var slice02 []int
if slice02 == nil {
fmt.Println(slice02 == nil)
fmt.Println("切片空", slice02)
}
// 初始化切片
slice03 := []int{1, 2, 3, 4}
fmt.Println("slice03有值切片:", slice03)
fmt.Printf("%T\n", slice03)
fmt.Println("slice03切片长度:", len(slice03))
fmt.Println("slice03切片容量:", cap(slice03))
}
make 定义切片
package main
import "fmt"
func main() {
// make 函数 ----> 创建切片
slice004 := make([]int, 5, 10)
fmt.Printf("slice004切片数据:%T\n", slice004)
fmt.Printf("slice004切片长度:%d\n", len(slice004))
fmt.Printf("slice004切片容量:%d\n", cap(slice004))
// 容量为5 能放6个数据吗? 【不能,超出容量】
//slice004[6] = 1
//fmt.Println(slice004) // index out of range [6] with length 5
// 切片如何扩容. append
slice004 = append(slice004, 7, 1)
fmt.Println(slice004)
// 容量也会扩容. 遵循二倍扩容:1.当前容量两扩大1倍数.
slice004 = append(slice004, 7, 1, 2, 37, 1, 2, 37, 1, 2, 37, 1, 2, 37, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6)
slice004 = append(slice004, 7, 1, 2, 37, 1, 2, 37, 1, 2, 37, 1, 2, 37, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6)
fmt.Println("扩容后的slice004:", slice004)
fmt.Printf("扩容后slice004切片数据:%T\n", slice004)
fmt.Printf("扩容后slice004切片长度:%d\n", len(slice004))
fmt.Printf("扩容后slice004切片容量:%d\n", cap(slice004))
}
切片追加
package main
import "fmt"
func main() {
// 切片追加: ...切片 表示拆解切片内的元素
slice05 := make([]int, 0, 3)
slice06 := []int{1, 2, 3, 4, 5, 6}
// 将 slice06 追加到 slice05 中
// slice06... 。即: 将slice06 进行了结构操作,循环 slice06中的每一个元素
slice05 = append(slice05, slice06...)
fmt.Println("slice05:", slice05)
}
遍历切片
package main
import "fmt"
func main() {
// 遍历切片
ergodicSlice1 := []int{1, 2, 3, 4}
for i := 0; i < len(ergodicSlice1); i++ {
fmt.Println(ergodicSlice1[i])
}
ergodicSlice2 := []int{1, 2, 3, 4}
for index, sliceVal := range ergodicSlice2 {
fmt.Println(index, sliceVal)
}
}
切片内存分析
- 切片 容量扩充/扩容内存 分析
- cap 成倍增加。容量超过1024,则按照1.2倍数增长
- 容量增加,内存地址就会发生变化
package main
import "fmt"
func main() {
// 切片 容量扩充/扩容内存 分析
// cap 成倍增加。容量超过1024,则按照1.2倍数增长
// 容量增加,内存地址就会发生变化
sliceMemory := []int{1, 2, 3}
fmt.Printf("切片长度:%d 切片容量:%d\n", len(sliceMemory), cap(sliceMemory))
fmt.Printf("切片地址:%p\n", sliceMemory)
sliceMemory = append(sliceMemory, 1, 2)
fmt.Printf("切片长度:%d 切片容量:%d\n", len(sliceMemory), cap(sliceMemory))
fmt.Printf("切片地址:%p\n", sliceMemory)
sliceMemory = append(sliceMemory, 2, 3)
fmt.Printf("切片长度:%d 切片容量:%d\n", len(sliceMemory), cap(sliceMemory))
fmt.Printf("切片地址:%p\n", sliceMemory)
/*
总结:
- 1. 每一个切片,底层是数组
- 2. 切片本身不存储数据,而是通过底层数组存储数据。修改切片的容量,也就修改数组中的数据,内存地址发生变化
- 3. append 追加数据/切片扩容时。只要容量够用,指向同一个【内存地址的数组】
- 4. 数组属于值类型copy
*/
}
切片扩容
package main
import "fmt"
func main() {
// 通过使用 copy 函数 实现切片make扩容,copy实现原数据到新切片
sliceCopyBefore := []int{1, 2, 3}
fmt.Printf("原切片。长度:%d, 容量:%d\n", len(sliceCopyBefore), cap(sliceCopyBefore))
fmt.Printf("原切片内存地址:%p\n", sliceCopyBefore)
// 1. make 扩容 新切片
sliceCopyAfter := make([]int, cap(sliceCopyBefore)*2)
// 2. 通过 copy 将 原切片内的数组中数据拷贝到新的切片数组中的数据
copy(sliceCopyAfter, sliceCopyBefore)
fmt.Printf("新切片。长度:%d, 容量:%d\n", len(sliceCopyAfter), cap(sliceCopyAfter))
fmt.Printf("新切片内存地址:%p\n", sliceCopyAfter)
}
数组的切片
package main
import "fmt"
func main() {
// 数组:连续的内存地址
// 切片底层指向一个数组
arraySlice := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
arraySlice01 := arraySlice[0:3] // 指向同一个地址 。 内存地址:0xc000026140
arraySlice02 := arraySlice[:5] // 指向同一个地址 。 内存地址:0xc000026140
arraySlice03 := arraySlice[2:5] // 内存地址发生变化
arraySlice04 := arraySlice[6:] // 内存地址发生变化
arraySlice05 := arraySlice[:10] // 指向同一个地址 。 内存地址:0xc000026140
/*
结果:
- 1. 使用 [start:end] 对数组进行切片
- 2. 起始位置从头开始,则使用同一块数组内存地址。
- 3. 从中间位置开始 切。 容量会切到最后。eg [2:5],容量为8,长度为3
- 4. 数组, 使用 [start:end] 结果会变成 切片类型
- 5. 容量不变。修改数组和切片。指向同一个数据。
- 6. 容量扩容。切片地址发生内存变化
*/
fmt.Printf("arraySlice01 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice01), cap(arraySlice01), arraySlice01, arraySlice01)
fmt.Printf("arraySlice02 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice02), cap(arraySlice02), arraySlice02, arraySlice02)
fmt.Printf("arraySlice03 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice03), cap(arraySlice03), arraySlice03, arraySlice03)
fmt.Printf("arraySlice04 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice04), cap(arraySlice04), arraySlice04, arraySlice04)
fmt.Printf("arraySlice04 最新截断的第一个元素的内存地址:%p\n", arraySlice04)
fmt.Printf("arraySlice 第6个元素的内存地址:%p\n", &arraySlice[6])
fmt.Printf("arraySlice05 数组切片后。长度:%d,容量:%d, 类型:%T, 内存地址:%p\n", len(arraySlice05), cap(arraySlice05), arraySlice05, arraySlice05)
fmt.Printf("arraySlice05 数组第一个元素 内存地址:%p\n", arraySlice05)
}
切片的类型
package main
import "fmt"
func main() {
// 数组 是值类型
array1 := [3]int{1, 2, 3}
array2 := array1
array1[2] = 100
// 深拷贝。指向不同的内存地址
fmt.Printf("array1:%v,array2:%v\n", array1, array2) // array1:[1 2 100],array2:[1 2 3]
// 切片 是引用类型
// 浅拷贝,指向同一个内存地址
s1 := []int{1, 2, 3}
s2 := s1
s2[1] = 200
fmt.Printf("s1:%v,s2:%v\n", s1, s2) // s1:[1 200 3],s2:[1 200 3]
}
切片如何实现深拷贝
- 使用make开辟新的切片
- 使用copy函数实现 切片深拷贝
package main
import "fmt"
func main() {
/*
// 切片如何实现 深拷贝
- 1. 使用make开辟新的切片
- 2. 使用copy函数实现 切片深拷贝
*/
s3 := []int{1, 2, 3, 4, 5}
s4 := make([]int, 0)
for _, i := range s3 {
s4 = append(s4, i)
}
// 修改s4
s4[3] = 100
fmt.Printf("s3:%p,s4:%p\n", s3, s4) // s3:0xc000024210,s4:0xc0000221c0
fmt.Printf("s3:%v,s4:%v\n", s3, s4) // s3:[1 2 3 4 5],s4:[1 2 3 100 5]
// 空类型 切片拷贝:copy 不会以追加方式拷贝,而是以相同位置替换。
// s3中的函数 拷贝到 s5 : 【 dst, src 】
s5 := []int{1, 1, 1, 1, 1, 1, 1, 1, 1}
copy(s5, s3)
fmt.Printf("s3:%p,s5:%p\n", s3, s5) // s3:0xc0000b8000,s5:0x1d97300
fmt.Printf("s3:%v,s5:%v\n", s3, s5)
// s6中的函数 拷贝到 s3 : 【 dst, src 】
// 空类型 切片拷贝:copy 不会以追加方式拷贝,而是以相同位置替换。
s6 := []int{1, 1, 1, 1, 1, 1, 1, 1, 1}
copy(s3, s6)
fmt.Printf("s3:%p,s6:%p\n", s3, s6) // s3:0xc000024210,s6:0xc000026140
fmt.Printf("s3:%v,s6:%v\n", s3, s6) // s3:[1 1 1 1 1],s6:[1 1 1 1 1 1 1 1 1]
}
数组和切片作为函数的参数
package main
import "fmt"
func updateSlice(s []int) {
fmt.Println("函数接收切片的值:", s)
s[2] = 100
fmt.Println("函数修改切片的值:", s)
}
func updateArray(a [3]int) {
fmt.Println("函数接收数组的值:", a)
a[2] = 100
fmt.Println("函数修改数组的值:", a)
}
func main() {
a1 := [3]int{1, 2, 3}
s1 := []int{1, 2, 3}
fmt.Println("切片传入函数前的值:", s1)
updateSlice(s1)
fmt.Println("切片传入函数后的值:", s1)
fmt.Println("-----------")
fmt.Println("数组传入函数前的值:", a1)
updateArray(a1)
fmt.Println("数组传入函数后的值:", a1)
}