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. 由数组创建
```go
var array = [...]int{0, 1, 2, 3, 4, 5, 6} // 创建一个有7个元素的数组
s1 := array[0:4] // 指定开始索引和结束索引进行切片
s2 := array[:4] // 只指定结束索引进行切片,开始索引默认为0
s3 := array[1:] // 只指定开始索引进行切片,结束索引默认为len(array)
s4 := array[:] // 不指定开始和结束索引
通过数组索引创建slice时,冒号前为开始索引,后面为结束索引,因此结束索引不能小于开始索引,切片时,不包含结束索引的值。
通过内置函数
make
创建make([]int, 10) // 创建一个len = 10 cap = 10 的slice
make([]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>
### Map
Go语言中内置的字典类型叫`map`。`map`的类型格式是`map[K]T`,其中K可以使任意可以进行比较的类型,T是值类型。map也是一种**引用类型**。
<a name="C0NYm"></a>
#### map的创建
1. 使用字面量创建
```go
m := map[string]int{"a": 1, "b": 10}
fmt.Println(m["a"])
fmt.Println(m["b"])
- 使用内置的make函数进行创建
m1 := make(map[string]int) // 创建一个map[] len=0
m1["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>
### Struct
Go中的struct由多个不同类型元素组合而成。这里面有两层含义:第一,struct结构中的类型可以是任意类型;第二,struct的存储空间是连续的,其字段按照声明时的顺序存放。<br />struct有两种形式:一种是struct类型字面量,一种是使用type声明的自定义struct类型。
<a name="obY81"></a>
#### struct的创建
```go
// 1. 使用类型字面量
struct {
FieldName FieldType
FieldName FieldType
}
// 2. 自定义struct类型
type TypeName struct {
FiledName FieldType
FiledName FieldType
FiledName FieldType
}
// 示例
type Person struct {
Name string
Age int
}
type Student struct {
*Person
Number 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 := &sureyee
fmt.Println(p.name) // sureyee
} ```