1.为什么需要切片
先看一个需求:
需要用一个数组保存学生的成绩,但是学生的个数是不确定的,请问怎么办?
解决方案:
使用切片
2.切片的基本介绍
(1).切片的英文名称是slice
(2).切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递机制
(3).切片的使用和数组类似,遍历切片,访问切片的元素和求切片的长度(len(slice))都是一样的
(4).切片的长度是可变的,因此切片是一个可以动态变化数组
(5).切片定义的基本语法:
var 切片名 []类型
比如: var a []int
package main
import (
"fmt"
)
func main() {
//演示切片的基本使用
var intArr [5]int = [...]int{1,2,3,4,5}
//声明/定义
//slice := intArr[1:3]
//1.slice 就是切片名
//2.intArr[1:3] 表示slice引用到intArr这个数组
//3.引用intArr这个数组的起始下标为1,最后的下标为3(但不包含3)
slice := intArr[1:3]
fmt.Println("intArr = ", intArr) //[1 2 3 4 5]
fmt.Println("slice 的元素是 = ", intArr) //[2 3]
fmt.Println("slice 的元素个数是= ", len(slice)) // 2
fmt.Println("slice 的容量 = ", cap(slice)) // 切片的容量是可以动态变化的
fmt.Printf("intArr[1]的地址: %p\n", &intArr[1]) // intArr[1]的地址: 0xc00000a39
fmt.Printf("slice[0]的地址: %p, slice[0]的值: %v,\n", &slice[0], slice[0]) //slice[0]的地址: 0xc00000a398, slice[0]的值: 2
slice[1] = 33
fmt.Println("intArr = ", intArr) //[1 33 3 4 5]
fmt.Println("slice 的元素是 = ", intArr) //[2 33]
}
3.切片在内存中的形式
基本介绍
为了深刻理解切片,画图分析切片在内存中是如何布局的
package main
import (
"fmt"
)
func main() {
//演示切片的基本使用
var intArr [5]int = [...]int{1,2,3,4,5}
//声明/定义
//slice := intArr[1:3]
//1.slice 就是切片名
//2.intArr[1:3] 表示slice引用到intArr这个数组
//3.引用intArr这个数组的起始下标为1,最后的下标为3(但不包含3)
slice := intArr[1:3]
fmt.Println("intArr = ", intArr) //[1 2 3 4 5]
fmt.Println("slice 的元素是 = ", intArr) //[2 3]
fmt.Println("slice 的元素个数是= ", len(slice)) // 2
fmt.Println("slice 的容量 = ", cap(slice)) // 切片的容量是可以动态变化的
fmt.Printf("intArr[1]的地址: %p\n", &intArr[1]) // intArr[1]的地址: 0xc00000a39
fmt.Printf("slice[0]的地址: %p, slice[0]的值: %v,\n", &slice[0], slice[0]) //slice[0]的地址: 0xc00000a398, slice[0]的值: 2
slice[1] = 33
fmt.Println("intArr = ", intArr) //[1 33 3 4 5]
fmt.Println("slice 的元素是 = ", intArr) //[2 33]
}
slice底层实现的原理是通过数组来实现的,Slice是由三个部分组成的:指针、长度和容量:
- 指针指向底层数组的第一个元素
- 长度表示slice当前包含的元素数量
- 容量表示底层数组从指针开始可访问的元素数量
当创建一个slice时,Go会自动创建一个底层数组,并将指针指向该数组的首个元素,同时将长度和容量初始化为相同的值。当slice添加元素时,如果元素的数量超过了slice的容量,Go会自动创建一个新的底层数组,并将原有元素复制到新的数组中。这样可以保证slice的连续性。当slice被传递给函数时,函数接收的是slice的副本,但是该副本会共享底层数组。因此,通过函数修改slice中的元素会影响到原有的slice和底层数组.
总结起来,slice底层实现的原理是通过指针、长度和容量来引用和管理底层数组,保证了slice的连续性和共享性,这种设计使得slice在性能和灵活性上都具有优势