GO数组 切片映射

44 阅读5分钟

数组

在GO中,总是会使用对应类型的零值来初始化变量。

如果用...说明可以通过数组长度来初始化 array := [...]int{10,20,30,40,50}

可以制定特定元素赋值 array := [5]int{1:10,2:20}

同其他语言不同,在go中数组是一个值,而不是一个指针,可以进行赋值 attry1 = array2 但是保证数组长度和类型都是一致的才可以赋值

func foo(array *[1e6]int) {  // 必须要是指向长度为1e6的数组的指针,强化了数组是一个值的概念
	return
}

func main(){
	fmt.Println("fuck world")
	// array := [...]int {10,20,390}

	var array [1e6]int
	foo(&array)
}

切片

切片是按照动态数组来构建的,可以自动增长和缩小。 切片的底层内存也是在连续块中分配的

切片的三个字段数据结构: 指向底层数组的指针,长度,容量

创建和初始化

如果只指定长度,那么切片的容量和长度相等 slice := make([]string,5) 分别指明的话,第一个位长度,第二个为容量,长度小于容量

多余的空余容量可以通过基于这个切片的切片访问,也可以通过后期合并在切片中

切片字面量: slice := []string {'red',"blue"} 定义类似于数组,但是[]里面不需要加东西 这种初始化长度和容量相等

如和设置初始化的长度和容量呢 slice := []int{99 : 0}

nil切片和空切片

只声明不做任何事的时候,就会创建nil切片。 var slice []int

空切片: slice := []int{}

分别表示没有收到数据和数据为空

使用切片

切片的赋值操作等使用和数组一致,即使用下标。

使用切片创造切片 newslice := slice[1:3] 长度为 3-1 容量位k-1

这两个切片共享底层数组。一个修改了,另一个也能感知到。

切片相比于数组来说,优势就是可以动态增加容量 newslice = append(newslice,60) 使用容量来添加一个长度,并赋值. append还是可变参数,若使用...运算符,可以把一个切片的所有元素追加进来.

如果底层数组里没有多的容量,那么go就会创建一个新的底层数组将被引用的现有的值赋值到新数组里,在追加新的值。 append很智能,当容量小于1000的时候,总是成倍增长,一旦超过一千,可能就是1.25的增长。

用三个索引来创建切片 slice := source[i:j:k] 长度: j - i; 容量: k-i 具体涵义:从i下标开始到j下标是长度,到k下标是容量

三个索引的意义:

  • 当基于切片创造切片后,因为这些切片都共享一个底层数组,但是呢append后又会分配新的容量到长度里面,同时为这个空闲容量赋值。当容量不够时,可能还会创建新的数组。 所以对单个切片的修改很容易影响到多个切片,但是又很难找到问题所在。 因此引入三个索引,控制子切片的长度和容量相等,当append时,就会分配新数组,不用担心会影响其他切片且保证了底层数组的整洁。

遍历切片 Range

range 会返回两个返回值:当前元素的索引,当前元素的副本。 缺点就是每次都只能从头开始遍历。

多维切片

slice := [][]int {{0},{10,20}} 每一个元素都是一个切片

函数间传递切片

切片本身不大,它就是指针加上来长度和容量。 所以,我们一般用值传递的方式传递切片。这也是切片效率高的原因

func foo(slice []int){
	fmt.Println("fuck world")
}


func main(){
	fmt.Println("fuck world")
	slice := make([]int,1e6)

	foo(slice)
}

映射 类似hash

映射是==无序==的,即便使用同样的顺序保存键值对,每次迭代映射的时候也不一样。因为它使用了散列表

散列表

桶 : 散列表的存储单元。

对于每一个键,通过散列函数会得到散列值。其中散列值的低位被用来是选择桶。

散列表用两个数据结构存储数据:数组:主要由用于区分每个键值对要存放在哪一个桶里面。存储的是散列值的高八位值。 第二个数据结构是字节数组:存储数值对。字节数组,先优先存储了桶里面的所有键,在存储所有值。

创建和初始化

dicat := make(map[int]string)

dict := map[string]string {"REd" : "12123"}

包含切片,函数的结构类型不能作为映射的键,因为他们具有引用语义。 但是切片当然可以作为映射的值。

使用

基本和C的哈希表一样 nil映射不能存储数据

判断映射里是否有这个元素:

value,exits := colors["bue"]

if exits{
	fmt.Println(values)
}

当键不存在,映射也会返回该类型的零值。

range关键字迭代映射返回的是键值对,而不再是索引和值。

删除关键字 表示从colors映射里删除red关键字 delete(colors,"red")

函数间传递映射

在函数间一般直接以值的形式传递,==注意传递映射并不会制造出该映射的一个副本==。 当传递映射到函数后,对这个函数进行了的修改,所有对这个映射的引用都能察觉到。