Go数组和切片
一、内部实现
- 数组
数组是一个长度固定的数据类型,用于存储一段具有相同类型的元素的连续块。数组存储的类型可以是内置类型,如整型或者字符串,也可以是某种结构类型。 - 切片
切片是围绕动态数组的概念构建的,可以按需自动增长和缩小
切片是一个很小的对象,对底层数组进行了抽象,并提供了相关的操作方法。切片有3个字段分别是指向底层数组的指针
,切片访问的元素个数(即长度)
和切片允许增长到的元素个数(即容量)
二、区别
2.1、声明和初始化
数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//声明一个包含5个元素的整型数组,并设置为零值
var array [5]int
//使用数组字面量声明数组
array := [5]int{10,20,30,40,50}
//隐式声明数组长度
array := [...]int{10,20,30,40,50}
//声明数组并指定特定元素
array := [5]int{0:10,2:30}
//使用make
s2 = make([]int, 16)
s3 = make([]int, 10, 32)
printSlice(s2)
printSlice(s3)
// len=16, cap=16
// len=10, cap=32切片
1
2
3
4
5
6
7
8
9
10
11//使用make
//长度和容量都是5个元素
slice := make([]string, 5)
//长度为3,容量为5个元素
slice := make([]int, 3, 5)
//使用字面量声明
//长度和容量都是4个元素
slice := []string{"red","blue","green","yellow"}
//声明切片 并指定特定元素 长度容量都是100
slice := []string{99:"!!"}
2.2、赋值
数组
1
2
3
4
5
6
7
8
9
10func main() {
var array1[5]string
array2:=[5]string{"Red","Blue","Green","Yellow","Pink"}
//把array2的值复制到array1
array1=array2
array1[0] = "Black"
fmt.Println(array1)
fmt.Println(array2)
}
如图数组赋值仅仅是复制数组的值
- 切片
1 | func main() { |
切片赋值,仅仅是复制切片的指针、长度和容量
2.3、遍历
- 数组的遍历
1 | func arrRange() { |
2.4、值传递 && 引用传递
2.4.1、数组变量
1. 值传递
GO中数组就是一个变量 –> 不同大小就是不同类型
1 | func printArray(arr [5]int) { |
错误:
1
cannot use arr2 (type [3]int) as type [5]int in argument to printArray
第一个成功
第二个不成功,类型不匹配
- 数组值修改 – 引用传递
1 | func printArray2(arr *[5]int) { |
2.4.2、切片
Slice 本身没有数据,只是对底层 array 的一个 view,其截取大小只是修改了切片中的ptr和len但是cap为从当前ptr算起到,原切片长度 ^4ae9ee
slice 可以向后扩展,不可以向前扩展
s[i]不可以超越len(s),向后扩展不可以超越cap(s)
如图:
^a7c516- 指针引用传递
切片截取:
1 | func main() { |
输出:
1 | arr[2:6] = [2 3 4 5] |
切片数据修改:
1 | func updateSlice(s []int) { |
越界问题:
例一:✅
1
2
3
4
5arr = [...]int{0,1,2,3,4,5,6,7}
s1 = arr[2:6]
s2 = s1[3:6]
fmt.Println("s1 = ",s1)
fmt.Println("s2 = ",s2)结果:
1
2s1 = [2 3 4 5]
s2 = [5 6 7]例2:❌
1
fmt.Println(s1[4])
结果:
1
panic: runtime error: index out of range
原因:[[#^4ae9ee]]
2.5、扩容
2.5.1、切片扩容 Append
1 | arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7} |
capacity
满了才扩容,每次扩容两倍,所以和java
一样,数组最好知道容量,上来就建好。
2.5.1、数组扩容
只能复制