前言
上文 Golang 基本类型 中我们介绍了golang 基本类型的常见用法,本文将介绍 golang 中的复合数据类型,常用的复合数据类型有 array 数组,slice 切片,map 字典 和 struct 四种。
文章目录
数组
数组是一个由固定长度的特定类型元素组成的序列,由于长度固定,在实际业务场景下使用较为不便,因此在 go 中很少直接使用。
数组的长度是数组类型的一个组成部分,因此 [3]int 和 [4]int 是两种不同的数组类型。数组的长度必须是常量表达式,因为数组的长度需要在编译阶段确定。
和大多数语言一样,go 的数组下表也是从 [0] 开始,到 [len - 1] 结束
var a [3]int
var q [3]int = [3]int{
1,2,3} // 1,2,3
var r [3]int = [3]int{
1,2} // 1,2,0
a[0] = 1
a[1] = 2
a[2] = 3
也可以使用 “…” 来声明数组,如果在数组的长度位置出现的是“…”省略号,则表示数组的长度是根据初始化值的个数来计算,因此,上面 q 数组的定义可以简化为
q := [...]int{
1,2,3}
fmt.Println(reflect.TypeOf(q)) // 输出 [3]int
对于较大的数组,可以指定一个索引和对应值列表的方式初始化,如下,定义了一个含有100个元素的数组r,索引为 13 的位置值为 21,最后一个元素被初始化为 -1,其它元素都是用 0 初始化。
r := [...]int{
13: 21, 99: -1}
Slice
Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。
go 的 slice 底层是由数组实现的,一个slice由三个部分构成:指针、长度和容量。创建 slice 时,指针指向第一个slice元素对应的底层数组元素的地址,长度对应slice中元素的数目,容量表示创建数组时分配空间的初始大小,长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。
和数组不同的是,slice 之间不能使用 ==
互相比较,slice 唯一合法的比较操作是和nil比较, 但是通常更推荐使用 len(s) == 0
来判断,而不是 s == nil
,否则对 []int{}
这种形式的 slice 判断会出现问题,可以参考如下代码。
var s []int // len(s) == 0, s == nil
s = []int(nil) // len(s) == 0, s == nil
s = []int{
} // len(s) == 0, s != nil
slice 基本操作
初始化
使用 make([]Type, len, cap)
初始化 slice, cap 参数可以缺省, 缺省时默认 cap 等于 len
sl_null := []int{
} // 创建空slice
sl0 := make([]int, 0, 3) // 创建 cap 为 3 的空 slice []
sl1 := make([]int, 0) // 创建 []
sl2 := make([]int, 3) // 创建 [0,0,0]
// 创建有初始内容的 slice
sl4 := []int{
1,2,3} // 类型为 []int
// 注意区分 slice 和 数组的初始化
// 数组的初始化为 s := [...]{1,2,3}, 类型为 [3]int
在 slice 末尾添加元素
添加元素时,如果添加完成后 len 大于当前 cap, slice 会进行扩容, 每次扩容 cap 的大小会翻一倍
sl3 = append(sl3, 4) // 添加单个元素
sl3 = append(sl3, 5, 6, 7) // 添加多个元素
sl4 := []int{
8, 9, 10}
sl3 = append(sl3, sl4...) // 将 sl4 展开,把所有元素添加到 sl3 末尾
// 修改 sl3 不会改变 sl4 的元素
获取 slice 长度和容量
内置的 len
和 cap
函数分别返回slice的长度和容量。
len_sl3 = len(sl3) // int
cap_sl3 = cap(sl3) // int
查看某元素是否在 slice 里
没有内置函数,需要自己遍历实现, 对 slice 遍历时取到两个值,第一个为 slice 的下标,第二个为下标对应的值。
for _, num := rang num_slice {
if num == target {
// ...
}