go 中的slice与数组
go 中的slice与数组
数组
go中的数组与C语言中的数组类似,但是不同的是C中的数组名其实还是指针,在作为参数传递的过程中会退化为指针,而go语言则是在编译期间就确定其大小,然后始终是作为值传递的。
初始化
[5] int {1,2,3,4,5}
长度为5的数组,其元素值依次为:1,2,3,4,5[5] int {1,2}
长度为5的数组,其元素值依次为:1,2,0,0,0 。在初始化时没有指定初值的元素将会赋值为其元素类型int的默认值0,string的默认值是""[...] int {1,2,3,4,5}
长度为5的数组,其长度是根据初始化时指定的元素个数决定的[5] int { 2:1,3:2,4:3}
长度为5的数组,key:value,其元素值依次为:0,0,1,2,3。在初始化时指定了2,3,4索引中对应的值:1,2,3[...] int {2:1,4:3}
长度为5的数组,起元素值依次为:0,0,1,0,3。由于指定了最大索引4对应的值3,根据初始化的元素个数确定其长度为5
作为参数传递
例如:
package main
import (
"fmt"
"reflect"
)
func modifySlice(array []int) {
array[0] = 10
}
func modifyArr(array [5]int) {
array[0] = 10
}
func modifyPt(array *[5]int){ // 作为指针传递
(*array)[0] = 10
}
func main(){
arr := [...]int{1,2,3,4,5}
fmt.Println(reflect.TypeOf(arr))
modifyArr(arr)
fmt.Println("In main(), arr values:", arr)
modifyPt(&arr)
fmt.Println("In main(), arr values:", arr)
sli := []int{1,2,3,4,5}
fmt.Println(reflect.TypeOf(sli))
modifySlice(sli)
fmt.Println("In main(), sli values:", sli)
}
// 输出结果为
//[5]int
//In main(), arr values: [1 2 3 4 5]
//In main(), arr values: [10 2 3 4 5]
//[]int
//5
//In main(), sli values: [10 2 3 4 5]
slice 切片
从上面的例子中可以看出slice作为参数传递的是指针,因此传递速度会快很多。
但是数组作为一个固定长度的数据类型,在使用中有很多不方便的地方,因此go提供了一个很类似python 中的list的数据类型slice
从名字也能看出来slice支持切片操作
sli := []int{1,2,3,4,5}
sli = sli[:3]
还支持append操作
sli = append(sli, 6)
sli = append(sli, sli2)
如果要实现类似数组的值传递的功能,可以利用 copy 函数
sli1 := make([]int, len(sli))
copt(sli1, sli)
初始化
- 可以通过make初始化
sli := make([]int, 5, 10) // 5 是其长度,10 是其容量(可选),分别可以通过 len(sli) cap(sli) 获取
- 直接初始化(初始长度为0)
var sli []int // sli = nil
- 从数组或slice初始化
sli := arr[:] // sli 的修改也会影响到arr
对比
从上面的内容可以看出数组与切片有以下区别
- 数组定长,定义的时候就需要确定,切片不定长
- 切片支持append、copy、切片操作
- 数组作为参数的时候是默认进行拷贝,值传递,而切片是引用传递
顺便说一下,slice的数据结构类似下面:
+--------------------+
| data pointer |
+--------------------+
| len |
+--------------------+
| cap |
+--------------------+
然后扩容方式与vector类似,1024字节以下是每次cap增加一倍,1024以上是每次cap增加1/4