转--Golang语言--复合数据

时间:2022-05-04
本文章向大家介绍转--Golang语言--复合数据,主要内容包括1、array、2、slice、3、map、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

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