一、切片的基本使用
1.直接声明创建切片
- (1)直接进行append追加操作
- (2)对数组进行截取
package main
import "fmt"
func main() {
var slice []int
var array [5]int = [5]int{2,2,2,2,2}
slice = append(slice, 1, 2, 3)
fmt.Println(slice)
slice = array[:len(array)]
fmt.Println(slice)
}
2.使用make创建切片
- (1)预留了内存,可以直接使用索引赋值和访问
- (2)也可以使用append进行元素追加
package main
import "fmt"
func main() {
slice := make([]int, 5)
slice = append(slice, 6)
slice[0] = 100
fmt.Println(slice)
}
3.对切片进行增删改查
(1)append的用法
package main
import "fmt"
func main() {
slice := make([]int, 5)
addend := make([]int, 10)
addend[8] = 800
// 1.追加单个元素
slice = append(slice, 6)
// 2.追加多个元素
slice = append(slice, 6, 7)
// 3.追加切片
slice = append(slice, addend ...)
// 4.追加临时切片
slice = append([]int{999,999}, slice ...)
fmt.Println(slice)
}
(2)copy的用法
- (1)多的拷贝到少的,会按照少的最大值拷贝
- (2)少的拷贝多的,会覆盖少的最大值数目的元素
package main
import "fmt"
func main() {
function1()
function2()
}
func function1 () {
var slice1 []int = []int{1, 2, 3}
var slice2 []int = []int{4, 5, 6, 7}
copy(slice1, slice2)
fmt.Println(slice1)
fmt.Println(slice2)
}
func function2 () {
var slice1 []int = []int{1, 2, 3}
var slice2 []int = []int{4, 5, 6, 7}
copy(slice2, slice1)
fmt.Println(slice1)
fmt.Println(slice2)
}
二、切片底层数据结构
1.切片的底层数据结构由三段数据组成:
- (1)指向数据头部的指针
- (2)切片的长度
- (3)切片的容量
2.切片上下界索引变化时内存变化原理
三、切片易错点
1.切片的内存增长的本质
1.内存拷贝
将源切片的内容拷贝到目的切片的内容
2.内存扩容
(1)扩容策略
a)如果cap<1024,按照每次2倍增长,否则按照cap的1/4增长
b)扩容是根据切片容量来的,而不是数组长度来的
(2)扩容之后是生成新数组还是复用老数组
a)如果切片append追加之后的总容量还是小于复用数组的长度,那就复用老数组
b)如果切片append追加之后的总容量大于数组的长度,那就会开辟新的空间,建立全新的数组,返回相应的切片引用
如下的例子可以说明扩容策略对切片的影响,在实际编码中应该注意多切片底层是共享数组的,改变一个切片的值,可能影响了其他多个切片:
2.切片作为函数入参是值传递,但是函数内部修改却能引起外部数据变化
- 1.切片作为函数入参传递的实质是值传递,但这点通过函数内外参数地址不一致可以确定
- 2.函数内外变化同步是因为切片底层数据指针进行了拷贝,是直接操作指针修改对应内存里的值,变相成为了地址传递
package main
import "fmt"
func changeSlice(s []int) {
fmt.Printf("func: %p \n", &s)
s[1] = 111
}
func main() {
slice := []int{0, 1, 2, 3}
fmt.Printf("slice: %v slice addr %p \n", slice, &slice)
changeSlice(slice)
fmt.Printf("slice: %v slice addr %p \n", slice, &slice)
}
3.切片初始化
切片使用make创建时,会自动给前len个元素赋值为0,append是基于len继续添加的,而不是基于0开始添加的
package main
import "fmt"
func main() {
function1()
function2()
}
func function1() {
s := make([]int, 5)
s = append(s, 1, 2, 3)
fmt.Println(s)
}
func function2() {
s := make([]int, 0)
s = append(s, 1, 2, 3)
fmt.Println(s)
}
4.切片截取与切片长度
(1)切片截取后,len会发生变化,可以通过len直接获取到长度
(2)切片截取使用[0:len]是获取当前所有元素,[0:len-1]才是获取除最后一个外的元素,右边的区间为开区间
package main
import "fmt"
func main() {
var arr []int = []int{1, 2, 3, 4}
fmt.Println(len(arr))
arr = arr[0 : len(arr) - 1]
fmt.Println(len(arr))
}