Go语言基本的复合数据类型有7种,分别是指针、数组、切片、字典、通道、结构和接口。

数组

数组的类型名是 [n]elementType ,其中n表示数组长度,elementType表示数组元素类型。数组一般在创建时,通过字面量初始化,单独声明一个数组类型变量而不进行初始化是没有意义的。

数组初始化

  1. var a [2]int // 声明一个有两个整型的数组
  2. a := [3]int{1,2,4} // 指定长度和初始化字面量
  3. a := [...]int{1, 2, 4} // 不指定长度,由后面的初始化列表数量来确定长度
  4. a := [3]int{1:1, 2:3} // 指定长度,并通过索引值进行初始化,没有初始化的元素使用类型默认值 [0,1,3]
  5. a := [...]int{1:1, 2:3} // 不指定总长度,通过索引值进行初始化,数组长度由最后一个索引值确定,没有指定索引的元素初始化为类型的零值 [0, 1, 3]
  6. a := [...]int{1:1, 2, 4} // 不指定总长度,进行初始化 [0, 1, 2, 4]

数组的特点

  1. 数组创建完长度就固定了,不可以再追加元素
  2. 数组是值类型的,数组赋值或作为函数参数都是值拷贝
  3. 数组长度是数组类型的组成部分,所以[10]int[20]int 表示不同的类型
  4. 可以根据数组创建切片

    数组的相关操作

    ```go var arr […]int{1, 2, 3, 4, 5} // 1. 访问数组里面的元素 b := arr[1] // 2

// 2. 遍历数组的元素 for i, v := range arr { fmt.Println(v)
}

// 获取数组的长度 l := len(arr) // 5

  1. <a name="M2XJz"></a>
  2. ### 切片
  3. `Slice`是一种可变长的数组,其数据结构中有指向数组的指针,所以是一种**引用类型**。Go为切片维护三个元素——指向底层数组的指针 `unsafe.Pointer`,切片的元素数量`len` 和底层数组的容量`cap`。
  4. <a name="3JJeU"></a>
  5. #### 切片的创建
  6. 1. 由数组创建
  7. ```go
  8. var array = [...]int{0, 1, 2, 3, 4, 5, 6} // 创建一个有7个元素的数组
  9. s1 := array[0:4] // 指定开始索引和结束索引进行切片
  10. s2 := array[:4] // 只指定结束索引进行切片,开始索引默认为0
  11. s3 := array[1:] // 只指定开始索引进行切片,结束索引默认为len(array)
  12. s4 := array[:] // 不指定开始和结束索引

通过数组索引创建slice时,冒号前为开始索引,后面为结束索引,因此结束索引不能小于开始索引,切片时,不包含结束索引的值。

  1. 通过内置函数make创建

    1. make([]int, 10) // 创建一个len = 10 cap = 10 的slice
    2. make([]int, 10, 15) // 创建一个len=10 cap=15的slice
  2. 字符串切片

    1. str := "hello,世界"
    2. b := []byte(str) // 字符串转为[]byte类型切片
    3. r := []rune(str) // 字符串转为[]rune类型切片

    切片支持的操作

  • 内置函数len()返回切片长度
  • 内置函数cap()返回切片底层数组容量
  • 内置函数append() 对切片追加元素
  • 内置函数copy() 用于复制一个切片 ```go a := […]int{0, 1, 2, 3, 4, 5, 6} b := make([]int, 2, 4) c := a[0:3]

fmt.Println(len(b)) // 2 fmt.Println(cap(b)) // 4 b = append(b, 1) // 将1追加到b中 fmt.Println(b) // [0, 0, 1] fmt.Println(len(b)) // 3 fmt.Println(cap(b)) // 4

b = append(b, c…) // 将c中的元素追加到b中 fmt.Println(b) // [0, 0, 1, 0, 1, 2] fmt.Println(len(b)) // 6 fmt.Println(cap(b)) // cap(b) == 8 ,底层数组发生扩展

d := make([]int, 2, 2) copy(d, c) // copy 复制c中的值到d中 fmt.Println(d) // [0, 1] fmt.Println(len(d)) // 2 fmt.Println(cap(d)) // 2

  1. <a name="aPZR0"></a>
  2. ### Map
  3. Go语言中内置的字典类型叫`map`。`map`的类型格式是`map[K]T`,其中K可以使任意可以进行比较的类型,T是值类型。map也是一种**引用类型**。
  4. <a name="C0NYm"></a>
  5. #### map的创建
  6. 1. 使用字面量创建
  7. ```go
  8. m := map[string]int{"a": 1, "b": 10}
  9. fmt.Println(m["a"])
  10. fmt.Println(m["b"])
  1. 使用内置的make函数进行创建
    1. m1 := make(map[string]int) // 创建一个map[] len=0
    2. m1["a"] = 1 // 对map添加元素
    3. fmt.Println(m1["a"])

    map支持的操作

  • map的单个键值访问的格式为mapName[key],更新某个key的值的格式为 mapName[key] = value
  • 可以使用 range 遍历一个map类型的变量,但是不保证每次迭代的顺序
  • 删除map中的某个键值,使用内置函数 delete 进行删除。delete(mapName, key)
  • 可以使用内置函数 len(mapName) 来获取map中的键值对的数量。 ```go m := make(map[int]string) m[1] = “zhangsan” m[2] = “lisi”

fmt.Println(len(m)) // 2 delete(m, 1) fmt.Println(m[2]) // lisi fmt.Println(len(m)) // 1

for k, v := range m { fmt.Println(“key=”, k, “value=”, v)
}

  1. <a name="2cjkT"></a>
  2. #### 注意
  3. - Go内置的map不是并发安全的,并发安全的map可以使用标准库sync中的map
  4. - 不要直接修改mao value内某个元素的值,如果想修改map的某个键值,则必须整体赋值。
  5. <a name="FxrEB"></a>
  6. ### Struct
  7. Go中的struct由多个不同类型元素组合而成。这里面有两层含义:第一,struct结构中的类型可以是任意类型;第二,struct的存储空间是连续的,其字段按照声明时的顺序存放。<br />struct有两种形式:一种是struct类型字面量,一种是使用type声明的自定义struct类型。
  8. <a name="obY81"></a>
  9. #### struct的创建
  10. ```go
  11. // 1. 使用类型字面量
  12. struct {
  13. FieldName FieldType
  14. FieldName FieldType
  15. }
  16. // 2. 自定义struct类型
  17. type TypeName struct {
  18. FiledName FieldType
  19. FiledName FieldType
  20. FiledName FieldType
  21. }
  22. // 示例
  23. type Person struct {
  24. Name string
  25. Age int
  26. }
  27. type Student struct {
  28. *Person
  29. Number int
  30. }
  31. // 【不推荐】初始化一,一旦struct增加字段,则整个初始化语句会出错
  32. a := Person{"Tom", 10}
  33. // 【推荐】初始化二,使用field初始化,没有指定的字段默认为零值
  34. p := &Person{
  35. Name: "张三",
  36. Age: 12, // 末尾处需要用逗号
  37. }
  38. s := Student {
  39. Person: p,
  40. Number: 1,
  41. }

接口

通道

指针

Go语言支持指针和多级指针。

  1. 在赋值语句中, *T 出现在 = 的左边表示指针声明,*T 出现在 = 右边表示取指针指向的值。

    1. g := "世界"
    2. var p *string = &g // 通过在变量名前加&来获取变量地址
    3. var p1 = *p // 获取指针值
    4. fmt.Println(p, p1) //0xc000096030 世界
  2. 结构体指针访问结构体字段仍然使用. 操作符。 ```go // 定义结构体 type User struct { name string age int }

func main() { sureyee := User{ name: “sureyee”, age: 28, }

  1. p := &sureyee
  2. fmt.Println(p.name) // sureyee

} ```