个人理解的复合数据是由其他数据格式复合而成。
1、array
数组的类型格式为单个数据单元类型+长度构成,如 [2]int,其中 [2] 代表数组的长度,而 int 代表每个单元都是整形。
数组的元素操作也是通过操作下标,即 arr[1] ,取出数组 arr 中的第2个元素,数组下标从0开始算起。
数组的长度可以通过 len(arr) 获取数组 arr 的长度。
1-1 声明和初始化
数组声明格式为 var 数组名 [数组长度]元素类型
例如:
var arr [2]int arr[0] = 1 // 声明以后,就可以使用index进行赋值
声明数组后,未进行初始化,则每个数据单元的初值是单元数据类型的默认值,例如 int 就是 0 ,string 是空 ""
声明的同时也可以初始化
var arr [2]int = [2]int{1, 2}
初始化数据的格式为: 数组类型 + 大括号 + 数组的数据
也可以使用:=来缩写
arr := [2]int{1, 2}
使用:=可以省略数组长度,而使用 [...] 让Go自动计算数组长度
arr := [...]int{1, 2}
PS:Go中的 ... 在别的地方还有很多,通常代表的意思是编译或运行时确定数目。
1-2 数组的嵌套
数组也可以作为另外一个数组的元素,这样就形成多维数组(嵌套数组)
arr := [2][2]int{[2]int{1, 2}, [2]int{3, 4}}
可以简写为
arr := [2][2]int{{1, 2}, {3, 4}}
同样嵌套数组的同纬度下的元素类型必须一致,例如
var arr [2][2]int
arr0 := [2]int{1, 2}
arr[0] = arr0
arr1 := [1]int{1}
arr[1] = arr1 // 编译报错:cannot use arr1 (type [1]int) as type [2]int in assignment
1-3 数组的长度
数组长度必须声明时给出,一旦给出以后便不能发生改变,可以通过len函数来获取数组的长度
1-4 数组的越界
如果下标小于0或者大于等于数组的长度
a、下标是数值常量,则编译报错:index out of bounds
b、下标是动态变量,则执行的时候检测,错误信息是 runtime error : index out of range
1-5 数组的赋值
array 赋值不同于 string , string 因为不能改变,所以只用传字符串的地址即可,而 array 因为能改变,所以要将整个内容复制,在内存中会有2份数据存在
arr1 := [2]int{1, 2}
var arr2 [2]int
arr2 = arr1
arr2[1] = 3
fmt.Print(arr1[1]) // 输出2
因为数组赋值需要占用空间,所以大多数情况是使用slice,用切片传递数组的地址的方式来减小内存的消耗。
2、slice
slice可以认为是个特殊的类数组的结构,其指向一个数组类型的数据,使用方式也同数组,越界报同数组一样的错误
2-1 slice 的声明
var s []int //不同于数组,长度是不指明的,如果指明则是一个数组
声明 slice 后,未进行初始化,则 slice 的值是 nil ,可以通过make进行默认值初始化,也可以使用具体值初始化。
默认值初始化(以下初始化都使用简短格式:=)
s := make([]int, 4, 4) // 第一个4为切片的长度,第二个为切片的容量,下面有解释
// 等同于 s := []int{0, 0, 0, 0}
具体值初始化的3种情况
a、指向已经存在的数组
arr := [4]int{1, 2, 3, 4}
s := arr[1:3]
b、创建一个(匿名)数组并且指向这个数组
s := []int{1, 2, 3, 4}
c、基于另一个slice
s1 := []int{1, 2, 3, 4}
s2 := s1[2:4]
2-2 slice 的结构
slice 的结构包含3部分:指向底层数据(起始下标)的指针、长度、容量。
长度同数组一样,使用len函数,容量则用cap函数
Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
Slice_a := Array_a[2:5]
例子的结构如下图所示(图片来自https://github.com/astaxie/build-web-application-with-golang)
按照数学上区间定义理解就是,array[i:j]的区间应该是[i,j),即包含的元素索引是 i <= index < j
上例中的 Array_a[2:5] 则包含的元素是:Array_a[2],Array_a[3] ,Array_a[4]
Slice_a 的 len() 等于 j - i
Slice_a 的 cap() 等于 len(Array_a) - i
如果i为0,j为array的长度,则可以忽略
Slice_a := Array_a[:] // 则包含数组的所有元素
2-3 slice的一些操作函数
除了上面已经说的make、len、cap函数之外,slice还支持append、copy操作函数
copy(dst, src) 从源src中复制元素到目标dst,并且返回复制的元素的个数,在Go语言中,几乎都遵循这样的次序,即目标参数在前,源参数再后
copy支持将string类型复制到字节切片,除此之外都必须类型相同
var byte_slice = make([]byte, 2)
copy(byte_slice, "hi")
append(dst, src) 将源src追加到目标dst中,其中源src可以是一个或者多个单一类型的值
int_slice := []int{1}
int_slice = append(int_slice, 2, 3) // [1, 2, 3]
也可以使另外一个切片,但是切片后面需要指定...特殊标记
int_slice := []int{1}
int_slice2 := []int{2, 3}
int_slice = append(int_slice, int_slice2...) // [1, 2, 3]
通样append也支持将string类型复制到字节切片,后面需要指定...特殊标记
var byte_slice = []byte("hello")
byte_slice = append(byte_slice, "world"...)
2-4 slice 的一些快捷操作
//在i位置后插入元素x
slice = append(slice[:i], append([]T{x}, slice[i:]...)...) // T的意思代表是某个数据类型
//在i位置后插入切片
slice1 = append(slice[:i], append(slice2, slice[i:]...)...)
//在i位置后插入j个空元素
slice = append(slice[:i], append(make([]T, j), lice[i:]...)...)
//切片追加单个元素
slice = append(slice, x)
//切片追加切片内容
slice1 = append(slice1, slice2...)
//切片追加 j个空元素
slice = append(slice, make([]T, j)...)
//复制切片
slice2 = make([]T, len(slice1))
copy(slice2, slice1)
//删除切片中的第i个元素
slice = append(slice[:i], slice[i+1:]...)
//删除切片中的指定元素集合[i:j]
slice = append(slice[:i], slice[j:]...)
// 弹出第一个元素
x, slice = slice[0], slice[1:]
// 弹出最后一个元素
x, slice = slice[len(slice)-1], slice[:len(slice)-1]
3、map
map在一些语言中称之为字典(Dictionary),也有称之为散列表(Hash Table) ,指的是一些类型的值到另一个类型的值的对应关系。
3-1 声明和初始化
map声明格式为 var map名 map[索引类型]元素类型
例如:
var map1 map[int]string
声明map后,未进行初始化,则map的值nil,还不能进行赋值,需要用make进行初始化
map1 = make(map[int]string)
声明的同时也可以初始化
var map1 map[int]string = make(map[int]string)
也可以使用:=来缩写
map1 := make(map[int]string)
也可以不用make,直接用值初始化
map1 := map[int]string{}
使用指定值初始化的时候,需要用key:value的格式
map1 := map[int]string{1:"1",2:"2"}
3-2 map操作
内置函数len通用可以用在map上,返回当前map中有多少个元素
map因为没有内存限制,可以很方便的添加,也可以很方便的删除,删除需要用delete,例如删除map1的key为1的元素为
delete(map1, 1)
获取map中的key的value
v := map[key]
判断是否存在某个key
v, ok := map[key]
key存在map中, v = key 的 value,ok = true
key不存在map中, v = T(default),ok = false
添加或者更改value
map[key] = value
注意 map 不保证 key - value 的存放顺序
key必须是支持比较运算符(== \ !=)的类型,如number、string、pointer、array、struct 、interface(接口实现类型必须支持比较运算符),不能是function、map、slice
有疑问加站长微信联系(非本文作者)