Go语言中数组、字符串和切片三者是密切相关的数据结构。这3种数据类型,在底层原始数据有着相同的内存结构,在上层,因为语法的限制而有着不同的行为表现。
数组
Go 语言里,数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块。数组存储的类型可以是内置类型,如整型或者字符串,也可以是某种结构类型。
数组是一种非常有用的数据结构,因为其占用的内存是连续分配的。
// 声明一个长度为5的int型数组arraryvar array [5]int// 声明数组并初始化array2 := [5]int{10, 20, 30, 40, 50}
如果使用…替代数组的长度,Go 语言会自动计算长度
array := [...]int{10, 20, 30, 40, 50}
使用数组
package mainimport "fmt"func main() {// 定义数组var arr [3]int// 可以设置初始值var arr2 = [...]int{1, 2, 3}// 指定索引初始化// 索引:初始值// [0,6,7]// 长度为最大索引下标元素为主,没有明确初始化的则为零值var arr3 = [...]int{1: 6, 2: 7}arr[0] = 1arr[0] = 0arr[0] = 1fmt.Println(arr)fmt.Println(arr2)fmt.Println(arr3)// 指针指向数组var p = &arrfmt.Println(p[0])// 指针迭代数组元素// index,valuefor i, v := range p {fmt.Println(i, v)}// 二维数组boxes := [2][2]int{{1, 0}, {0, 1}}// 访问二维数组fmt.Println(boxes[1][1])}
package mainimport ("fmt")func main() {// 固定长度数组 初始值默认为 0var arr [5]int// 初始化固定长度数组// 仅可通过简短变量初始化数组内容arr2:=[3]int{1,2,3}// 自动推断数组长度arr3:=[...]int{1,1,0,0}// len(数组名称) 来获得数组长度fmt.Println(len(arr),len(arr2),len(arr3))// 查看数组类型fmt.Printf("%T\n",arr)fmt.Printf("%T\n",arr2)fmt.Printf("%T\n",arr3)// 遍历数组for i:=0;i<len(arr2);i++{fmt.Println(arr2[i])}for i,v:=range arr3{fmt.Println("index=",i,"value=",v)}}
5 3 4[5]int[3]int[4]int123index= 0 value= 1index= 1 value= 1index= 2 value= 0index= 3 value= 0
- 需要注意的是数组作为函数参数传递时是按照值传递进行的
字符串
Go语言字符串底层数据也是对应的字节数组,但是字符串的只读属性禁止了在程序中对底层字节数组的元素的修改。字符串赋值只是复制了数据地址和对应的长度,而不会导致底层数据的复制。
切片
切片的行为更为灵活,切片的结构和字符串结构类似,但是解除了只读限制。切片的底层数据虽然也是对应数据类型的数组,但是每个切片还有独立的长度和容量信息,切片赋值和函数传参时也是将切片头信息部分按传值方式处理。
package mainimport "fmt"func printSlice(arr []int,title string) {fmt.Println("========",title,"========")fmt.Println("Length:",len(arr))for i,v:=range arr{fmt.Println("index=",i,"value=",v)}}func test(s []int) {s[0]=-1}func main() {// 定义一个sliceslice :=[]int{1,1,2,3,4}fmt.Printf("%T\n",slice)test(slice)printSlice(slice,"slice1")}
[]int======== slice1 ========Length: 5index= 0 value= -1index= 1 value= 1index= 2 value= 2index= 3 value= 3index= 4 value= 4
- 需要注意的是数组作为函数参数传递时是按照引用传递进行的
切片操作
- append 添加元素
- copy 拷贝切片
声明切片
package mainimport "fmt"func main() {// 声明并初始化 slices:= []int{1,2,3}fmt.Printf("len=%d,coll=%v\n",len(s),s)// 声明一个slicevar slice []intfmt.Printf("len=%d,coll=%v\n",len(slice),slice)// 开辟空间slice = make([]int,3,5)slice[0]=100fmt.Printf("len=%d,coll=%v\n",len(slice),slice)slice2 :=make([]int,2)fmt.Printf("len=%d,coll=%v\n",len(slice2),slice2)// 判断slice是否是空的两种方法if slice ==nil{fmt.Println("slice empty")}if len(slice2)==0 {fmt.Println("slice2 empty")}}
操作切片
package mainimport "fmt"func main() {slice :=make([]int,3,5)fmt.Printf("len=%d,cap=%d,coll=%v\n",len(slice),cap(slice),slice)// 添加元素slice = append(slice, 1)slice = append(slice, 2)slice = append(slice, 3)slice = append(slice, 4)slice = append(slice, 5)fmt.Printf("len=%d,cap=%d,coll=%v\n",len(slice),cap(slice),slice)}
len=3,cap=5,coll=[0 0 0]len=8,cap=10,coll=[0 0 0 1 2 3 4 5]

切片截取
- [start,end) 左闭右开
- [:4] 从头开始
- [2:] 截取到尾
- [:] 截取全部
package mainimport "fmt"func main() {slice:= []int{1,2,3,4,5,6,7,8,9,10}// 切片截取 左闭右开// [,)fmt.Printf("%v\n",slice[1:4])// copy 拷贝指定部分target :=make([]int,3)copy(target,slice)fmt.Printf("%v\n",target)// 将一个切片附加到另一个切片里 可以使用切片展开var target2 []int// xxxx... 展开切片target2 =append(target2,slice...)fmt.Printf("%v\n",target2)}
[2 3 4][1 2 3][1 2 3 4 5 6 7 8 9 10]
