Go语言基本的复合数据类型有7种,分别是指针、数组、切片、字典、通道、结构和接口。
数组
数组的类型名是 [n]elementType ,其中n表示数组长度,elementType表示数组元素类型。数组一般在创建时,通过字面量初始化,单独声明一个数组类型变量而不进行初始化是没有意义的。
数组初始化
var a [2]int // 声明一个有两个整型的数组a := [3]int{1,2,4} // 指定长度和初始化字面量a := [...]int{1, 2, 4} // 不指定长度,由后面的初始化列表数量来确定长度a := [3]int{1:1, 2:3} // 指定长度,并通过索引值进行初始化,没有初始化的元素使用类型默认值 [0,1,3]a := [...]int{1:1, 2:3} // 不指定总长度,通过索引值进行初始化,数组长度由最后一个索引值确定,没有指定索引的元素初始化为类型的零值 [0, 1, 3]a := [...]int{1:1, 2, 4} // 不指定总长度,进行初始化 [0, 1, 2, 4]
数组的特点
- 数组创建完长度就固定了,不可以再追加元素
- 数组是值类型的,数组赋值或作为函数参数都是值拷贝
- 数组长度是数组类型的组成部分,所以
[10]int和[20]int表示不同的类型 - 可以根据数组创建切片
数组的相关操作
```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
<a name="M2XJz"></a>### 切片`Slice`是一种可变长的数组,其数据结构中有指向数组的指针,所以是一种**引用类型**。Go为切片维护三个元素——指向底层数组的指针 `unsafe.Pointer`,切片的元素数量`len` 和底层数组的容量`cap`。<a name="3JJeU"></a>#### 切片的创建1. 由数组创建```govar array = [...]int{0, 1, 2, 3, 4, 5, 6} // 创建一个有7个元素的数组s1 := array[0:4] // 指定开始索引和结束索引进行切片s2 := array[:4] // 只指定结束索引进行切片,开始索引默认为0s3 := array[1:] // 只指定开始索引进行切片,结束索引默认为len(array)s4 := array[:] // 不指定开始和结束索引
通过数组索引创建slice时,冒号前为开始索引,后面为结束索引,因此结束索引不能小于开始索引,切片时,不包含结束索引的值。
通过内置函数
make创建make([]int, 10) // 创建一个len = 10 cap = 10 的slicemake([]int, 10, 15) // 创建一个len=10 cap=15的slice
字符串切片
str := "hello,世界"b := []byte(str) // 字符串转为[]byte类型切片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
<a name="aPZR0"></a>### MapGo语言中内置的字典类型叫`map`。`map`的类型格式是`map[K]T`,其中K可以使任意可以进行比较的类型,T是值类型。map也是一种**引用类型**。<a name="C0NYm"></a>#### map的创建1. 使用字面量创建```gom := map[string]int{"a": 1, "b": 10}fmt.Println(m["a"])fmt.Println(m["b"])
- 使用内置的make函数进行创建
m1 := make(map[string]int) // 创建一个map[] len=0m1["a"] = 1 // 对map添加元素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)
}
<a name="2cjkT"></a>#### 注意- Go内置的map不是并发安全的,并发安全的map可以使用标准库sync中的map- 不要直接修改mao value内某个元素的值,如果想修改map的某个键值,则必须整体赋值。<a name="FxrEB"></a>### StructGo中的struct由多个不同类型元素组合而成。这里面有两层含义:第一,struct结构中的类型可以是任意类型;第二,struct的存储空间是连续的,其字段按照声明时的顺序存放。<br />struct有两种形式:一种是struct类型字面量,一种是使用type声明的自定义struct类型。<a name="obY81"></a>#### struct的创建```go// 1. 使用类型字面量struct {FieldName FieldTypeFieldName FieldType}// 2. 自定义struct类型type TypeName struct {FiledName FieldTypeFiledName FieldTypeFiledName FieldType}// 示例type Person struct {Name stringAge int}type Student struct {*PersonNumber int}// 【不推荐】初始化一,一旦struct增加字段,则整个初始化语句会出错a := Person{"Tom", 10}// 【推荐】初始化二,使用field初始化,没有指定的字段默认为零值p := &Person{Name: "张三",Age: 12, // 末尾处需要用逗号}s := Student {Person: p,Number: 1,}
接口
通道
指针
Go语言支持指针和多级指针。
在赋值语句中,
*T出现在=的左边表示指针声明,*T出现在=右边表示取指针指向的值。g := "世界"var p *string = &g // 通过在变量名前加&来获取变量地址var p1 = *p // 获取指针值fmt.Println(p, p1) //0xc000096030 世界
结构体指针访问结构体字段仍然使用
.操作符。 ```go // 定义结构体 type User struct { name string age int }
func main() { sureyee := User{ name: “sureyee”, age: 28, }
p := &sureyeefmt.Println(p.name) // sureyee
} ```
