Go语言中数组是具有固定长度而且拥有零个或者多个相同或相同数据类型元素的序列。由于数组长度固定,所以在Go语言比较少直接使用。而slice长度可增可减,使用场合比较多。更深入的区别在于:数组在使用的过程中都是值传递,将一个数组赋值给一个新变量或作为方法参数传递时,是将源数组在内存中完全复制了一份,而不是引用源数组在内存中的地址。为了满足内存空间的复用和数组元素的值的一致性的应用需求,Slice出现了,每个Slice都是都源数组在内存中的地址的一个引用,源数组可以衍生出多个Slice,Slice也可以继续衍生Slice在理解slice之前,我们还是了解下数组。
数组
Go语言数组中每个元素是按照索引来访问的,索引从0到数组长度减1。Go语言内置函数len可以返回数组中的元素个数。
初始化
数组初始化的方式:
var a [3] int //3个整数型的数组,初始值是3个0
arr:=[5]int{1,2,3,4,5} //长度为5
var array2 = [...]int{6, 7, 8} //不声明长度
q := [...] int {1,2,3} //不声明长度
r := [...] int {99:-1} //长度为100的数组,只有最后一个是-1,其他都是0
总之,初始化方式有四种,二二组合:(不)指定长度*初始化部分、全部元素。
Go语言中数组也可以作为参数:
package main
import "fmt"
func modify_arr(array [5]int) {
array[0]=10
fmt.Println("In modify_arr,array values is:",array)
}
func main() {
arr:=[5]int{1,2,3,4,5}
modify_arr(arr)
fmt.Println("In main,array values is:",arr)
}
slice
slice表示一个拥有相同类型元素的可变长度序列。slice通常被写为[]T,其中元素的类型都是T;它看上去就像没有长度的数组类型。
数组和slice其实是紧密关联的。slice可以看成是一种轻量级的数据结构,可以用来访问数组的部分或者全部元素,而这个数组称之为slice的底层数组。slcie有三个属性:指针,长度和容量。指针指向数组的第一个可以从slice中访问的元素,这个元素不一定是数组的第一个元素。长度指的是slice中的元素个数,不能超过slice的容量。指针通常是从指向数组的第一个可以从slice中访问的元素,这个元素不一定是数组的第一个元素。长度指的是slice中的元素个数,它不能超过slice的容量。容量的大小通常大于等于长度,会随着元素个数增多而动态变化。Go语言的内置函数len 和 cap 用来返回slice的长度和容量。
初始化
slice初始化的方式:
s1 := []int{1, 2, 3} //注意与数组初始化的区别,在内存中构建一个包括有3个元素的数组,然后将这个数组的应用赋值给s这个Slice
a := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} //a是数组
s2 := a[2:8] //从数组中切片构建Slice
s3 := make([]int, 10, 20) //make函数初始化,len=10,cap=20
len和cap关系
在追加元素时,如果容量cap不足时,cap一般变为原来的2倍来实现扩容,见以下代码最后两个输出:
package main
import "fmt"
func print_info(my_slice[]int) {
fmt.Println("len :",len(my_slice))
fmt.Println("cap :",cap(my_slice))
for i,v :=range my_slice{
fmt.Println("element[",i,"]=",v)
}
}
func main() {
my_slice01:=[]int{1,2,3,4,5}
my_slice02:=make([]int,5)
my_slice03:=make([]int,5,6)
my_slice04:=append(my_slice03,8,9,10)
print_info(my_slice01)
print_info(my_slice02)
print_info(my_slice03)
print_info(my_slice04)
}
以上代码的输出如下:
len : 5
cap : 5
element[ 0 ]= 1
element[ 1 ]= 2
element[ 2 ]= 3
element[ 3 ]= 4
element[ 4 ]= 5
len : 5
cap : 5
element[ 0 ]= 0
element[ 1 ]= 0
element[ 2 ]= 0
element[ 3 ]= 0
element[ 4 ]= 0
len : 5
cap : 6
element[ 0 ]= 0
element[ 1 ]= 0
element[ 2 ]= 0
element[ 3 ]= 0
element[ 4 ]= 0
len : 8
cap : 12
element[ 0 ]= 0
element[ 1 ]= 0
element[ 2 ]= 0
element[ 3 ]= 0
element[ 4 ]= 0
element[ 5 ]= 8
element[ 6 ]= 9
element[ 7 ]= 10
slice的cap扩容规则:
- 如果新的大小是当前大小2倍以上,则直接扩容为这个新的cap;
- 否则循环以下操作:如果当前大小小于1024,按每次2倍增长,否则每次按当前大小1/4增长。直到增长的大小超过或等于新cap。
slice做函数参数
注意和数组作为函数参数的区别:
// slice01
package main
import (
"fmt"
)
func main() {
a := []int{1, 2, 3, 4, 5}
var b = a[0:3]
var c = [...]int{3, 6, 9, 2, 6, 4}
d := c[0:2]
sliceInfo(b)
fmt.Printf("sum of b is %d\n", sum(b))
fmt.Printf("sum of d is %d\n", sum(d))
}
func sum(a []int) int {
s := 0
for i := 0; i < len(a); i++ {
s += a[i]
}
return s
}
func sliceInfo(x []int) {
fmt.Printf("len is %d ,cap is %d, slice is %v\n", len(x), cap(x), x)
}