Go语言中数组、字符串和切片三者是密切相关的数据结构。这3种数据类型,在底层原始数据有着相同的内存结构,在上层,因为语法的限制而有着不同的行为表现。

数组

Go 语言里,数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块。数组存储的类型可以是内置类型,如整型或者字符串,也可以是某种结构类型。

数组是一种非常有用的数据结构,因为其占用的内存是连续分配的。

  1. // 声明一个长度为5的int型数组arrary
  2. var array [5]int
  3. // 声明数组并初始化
  4. array2 := [5]int{10, 20, 30, 40, 50}

如果使用…替代数组的长度,Go 语言会自动计算长度

  1. array := [...]int{10, 20, 30, 40, 50}

使用数组

  1. package main
  2. import "fmt"
  3. func main() {
  4. // 定义数组
  5. var arr [3]int
  6. // 可以设置初始值
  7. var arr2 = [...]int{1, 2, 3}
  8. // 指定索引初始化
  9. // 索引:初始值
  10. // [0,6,7]
  11. // 长度为最大索引下标元素为主,没有明确初始化的则为零值
  12. var arr3 = [...]int{1: 6, 2: 7}
  13. arr[0] = 1
  14. arr[0] = 0
  15. arr[0] = 1
  16. fmt.Println(arr)
  17. fmt.Println(arr2)
  18. fmt.Println(arr3)
  19. // 指针指向数组
  20. var p = &arr
  21. fmt.Println(p[0])
  22. // 指针迭代数组元素
  23. // index,value
  24. for i, v := range p {
  25. fmt.Println(i, v)
  26. }
  27. // 二维数组
  28. boxes := [2][2]int{{1, 0}, {0, 1}}
  29. // 访问二维数组
  30. fmt.Println(boxes[1][1])
  31. }
  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. // 固定长度数组 初始值默认为 0
  7. var arr [5]int
  8. // 初始化固定长度数组
  9. // 仅可通过简短变量初始化数组内容
  10. arr2:=[3]int{1,2,3}
  11. // 自动推断数组长度
  12. arr3:=[...]int{1,1,0,0}
  13. // len(数组名称) 来获得数组长度
  14. fmt.Println(len(arr),len(arr2),len(arr3))
  15. // 查看数组类型
  16. fmt.Printf("%T\n",arr)
  17. fmt.Printf("%T\n",arr2)
  18. fmt.Printf("%T\n",arr3)
  19. // 遍历数组
  20. for i:=0;i<len(arr2);i++{
  21. fmt.Println(arr2[i])
  22. }
  23. for i,v:=range arr3{
  24. fmt.Println("index=",i,"value=",v)
  25. }
  26. }
  1. 5 3 4
  2. [5]int
  3. [3]int
  4. [4]int
  5. 1
  6. 2
  7. 3
  8. index= 0 value= 1
  9. index= 1 value= 1
  10. index= 2 value= 0
  11. index= 3 value= 0
  • 需要注意的是数组作为函数参数传递时是按照值传递进行的

字符串

Go语言字符串底层数据也是对应的字节数组,但是字符串的只读属性禁止了在程序中对底层字节数组的元素的修改。字符串赋值只是复制了数据地址和对应的长度,而不会导致底层数据的复制。

切片

切片的行为更为灵活,切片的结构和字符串结构类似,但是解除了只读限制。切片的底层数据虽然也是对应数据类型的数组,但是每个切片还有独立的长度和容量信息,切片赋值和函数传参时也是将切片头信息部分按传值方式处理。

  1. package main
  2. import "fmt"
  3. func printSlice(arr []int,title string) {
  4. fmt.Println("========",title,"========")
  5. fmt.Println("Length:",len(arr))
  6. for i,v:=range arr{
  7. fmt.Println("index=",i,"value=",v)
  8. }
  9. }
  10. func test(s []int) {
  11. s[0]=-1
  12. }
  13. func main() {
  14. // 定义一个slice
  15. slice :=[]int{1,1,2,3,4}
  16. fmt.Printf("%T\n",slice)
  17. test(slice)
  18. printSlice(slice,"slice1")
  19. }
  1. []int
  2. ======== slice1 ========
  3. Length: 5
  4. index= 0 value= -1
  5. index= 1 value= 1
  6. index= 2 value= 2
  7. index= 3 value= 3
  8. index= 4 value= 4
  • 需要注意的是数组作为函数参数传递时是按照引用传递进行的

切片操作

  • append 添加元素
  • copy 拷贝切片

声明切片

  1. package main
  2. import "fmt"
  3. func main() {
  4. // 声明并初始化 slice
  5. s:= []int{1,2,3}
  6. fmt.Printf("len=%d,coll=%v\n",len(s),s)
  7. // 声明一个slice
  8. var slice []int
  9. fmt.Printf("len=%d,coll=%v\n",len(slice),slice)
  10. // 开辟空间
  11. slice = make([]int,3,5)
  12. slice[0]=100
  13. fmt.Printf("len=%d,coll=%v\n",len(slice),slice)
  14. slice2 :=make([]int,2)
  15. fmt.Printf("len=%d,coll=%v\n",len(slice2),slice2)
  16. // 判断slice是否是空的两种方法
  17. if slice ==nil{
  18. fmt.Println("slice empty")
  19. }
  20. if len(slice2)==0 {
  21. fmt.Println("slice2 empty")
  22. }
  23. }

操作切片

  1. package main
  2. import "fmt"
  3. func main() {
  4. slice :=make([]int,3,5)
  5. fmt.Printf("len=%d,cap=%d,coll=%v\n",len(slice),cap(slice),slice)
  6. // 添加元素
  7. slice = append(slice, 1)
  8. slice = append(slice, 2)
  9. slice = append(slice, 3)
  10. slice = append(slice, 4)
  11. slice = append(slice, 5)
  12. fmt.Printf("len=%d,cap=%d,coll=%v\n",len(slice),cap(slice),slice)
  13. }
  1. len=3,cap=5,coll=[0 0 0]
  2. len=8,cap=10,coll=[0 0 0 1 2 3 4 5]

2. 数组,字符串,切片 - 图1

切片截取

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