Go语言的三种数据结构:数组、切片和映射,其功能类似于Python中的列表、切片和字典。
1、在GO语言里,数组是一个长度固定的数据类型,用于存储一段具有相同类型的元素的连续块。数组存储的结构可以是内置类型,如整型或者字符串,也可以是某种结构类型。
数组的索引从零开始,即数组中第一个元素的索引为0。
GO中的切片和Python中的切片功能一样,但是GO不支持负索引。
切片的内部结构包括底层数组指针、大小和容量。它通过指针引用底层数组,把对数据的读写操作限定在知道的区域内。
切片作为指向原有数组的引用,对切片进行修改就是对原有数组进行修改。
切片的动态增长都是通过内置函数append来实现的。
切片扩容:
//原切片长度低于1024时直接翻倍
//原切片长度大于等于1024时,每次只增加25%,直到满足需要的容量
容量足够的切片直接将append添加的新元素覆盖到原有数组中,容量不够的切片进行扩容操作,申请了新的底层数组,不在原数组的基础上进行操作。扩容的过程:申请一个新的连续内存空间,空间大小一般为原有容量的两倍,然后将原来数组中的数据复制到新的数组中,同时将切片的指针指向新的数组,最后将新的元素添加到新的数组中。
go的列表list :通过双向链表的方式实现,能够高效地进行元素的插入和删除操作。双向链表中每个元素都持有其前后元素的引用,在列表进行向前或者向后遍历时会非常方便;但是,进行元素的插入和删除时需要同时修改前后元素的持有引用。
list是一个带有头结点的链表,头结点中并不存储数据。
list初始化:
var 那么list.List 或者 name:= list.New() //下面是列表的插入、删除和遍历操作:
package main
import (
"container/list"
"fmt"
)
func main(){
tmpList := list.New()
for i:=0;i<-10;i++{
tmpList.PushBack(i) //插入元素
}
first := tmpList.PushFront(0)
tmpList.Remove(first) //删除
for l:= tmpList.Front();l != nil ;l = l.next(){ //遍历list
fmt.Println(l.value," ")
}
}
GO中切片和数组声明是的区别在于是否指定了数组长度。
切片类型 | 声明方法 | 适用场合 | 共同点 |
---|---|---|---|
nil切片 | var slice [] datatype | 描述一个不存在的切片时,nil 切片会很好用。 nil切片可以用于很多标准库和内置函数。 | nil切片:长度为0,容量为0 |
空切片 | slice := make([]datatype, 0)或 slice := [] datatype{} | 表示空集合时,空切片很有用。 | 空切片:长度为0,容量为0 |
对于底层数组容量是k的切片slice[i : j ] 来说:
长度:j - i
容量: k - i
切片长度指的是切片中元素的个数;切片的容量指的是从切片的第一个元素到底层数组最后一个元素的元素个数。
内置函数append是一个可变参数的函数,可以在一次调用传递多个追加的值,使用(. . .)运算符可以将切片的所有元素追加到另一个切片里。代码如下:
s1 := [ ] int {1, 2}
s2 := [ ] int {3, 4}
fmt.Printf("%v\n", append(s1, s2...))
2、映射是一种数据结构,用于存储一些列无序的键值对。
make声明映射:dict := make(map[键类型]值类型)
使用键值对初始化映射:dict := map[键类型]值类型{ 键:值,键:值}
//使用字符串切片作为映射的键:dict := map[[]string] int { }
//创建映射,使用字符串切片作为值 dict := map[ int ] [ ] string { }
//nil 映射的创建
var 映射名 map[键类型]值类型
但是nil映射不能用于存储键值对。
测试映射里是否存在某个键是映射的重要操作。从映射取值时有两个选择:
A. 同时获得值,以及表示这个键是否存在的标志,代码如下:
value, exists := colors[ "Blue"]
if exists {
fmt.Println(value)
}
在GO语言里,通过键来索引映射时,即便这个键不存在也总会返回一个值。这种情况下,返回的是该值对应的类型的零值。
defer 关键字:
defer可以注册多个延迟调用,这些调用以先进后出的顺序在函数返回前被执行。defer常用于保证一些资源最终能够得到回收和释放。
defer后面必须是函数或方法的调用。
defer 语句必须先注册后才能执行,如果defer位于return之后,则defer因为没有注册,不会执行。主动调用os.Exit(int)
退出进程时,defer将不再被执行。
defer也有明显的副作用:defer会推迟资源的释放,defer尽量不要放到循环语句中,将大函数内部的defer语句单独拆分成一个小函数是一种很好的实践方式。另外defer相对于普通函数的调用需要间接的数据结构的支持,相对于普通函数调用有一定的性能损耗。
小结:
数组是构造切片何映射的基石。
Go语言里切片经常用来处理数据的集合,映射用来处理具有键值对结构的数据。
内置函数make可以创建切片和映射,并制定原始的长度和容量。也可以直接使用切片和映射字面量,或者使用字面量作为变量的初始值。
切片没有容量限制,可以使用内置函数append函数扩展容量。
映射的增长没有容量或者任何限制。
内置函数len可以获取切片或者映射的长度,
内置函数cap只能用于切片。
通过组合可以创建多维数组和多维切片。也可以使用切片或者其他映射作为映射的值,但是切片不能作为映射的键。
将切片或者映射传递给函数成本很小,并且不会复制底层的数据结构。