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