slice

slice 是一个引用类型,其指向一个底层的数组。slice 是一个只有 3 个字段的数据结构:一个是指向底层数组的指针,一个是 slice 长度,一个是 slice 的容量

slice 的声明和初始化

使用 make 声明并初始化 slice

slice := make([]int, 5, 10)         //声明一个容量为 10, 元素个数为 5 且 5 个元素都初始化为 0 的 slice
fmt.Println(slice)                  //[0 0 0 0 0] 只能访问已初始化的 5 个元素, 剩余 5 个 int 的容量只有被扩充(appen)了才能被访问
fmt.Println(len(slice), cap(slice)) //长度和容量分别为 5 10

//make 声明 slice 中指定容量的参数可以省略, 默认容量大小和长度一致
a := make([]int, 5)
fmt.Println(len(a), cap(a)) //5 5

使用字面量创建一个 slice(类似于数组)

slice := []int{1, 2, 3, 4}          //注意, 没有指定长度创建的是 slice, 指定长度创建的是 array
fmt.Println(len(slice), cap(slice)) //4, 4

a := []int{5: 1} //指定下标为 5 的元素值为 1
fmt.Println(a)   //[0 0 0 0 0 1]

nil slice 和空 slice
注意:nil slice 不能 append 元素,也不能用 len, cpa 计算长度和容量

b := []int{}//一个元素集合为空的切片
fmt.Println(len(b), cap(b)) //0 0
b = append(b, 1)
	
c := []int//一个 nil 切片
//fmt.Println(len(c), cap(c)) // error type []int is not an expression
//c = append(c, 1) // error type []int is not an expression
slice 是引用类型

slice 之间无论是直接用 = 进行赋值操作,还是用 [:] 截取元素的形式进行赋值操作都是引用赋值,即指向同一个底层数组

package main

import (
	"fmt"
)

func main() {
	a := make([]int, 4, 6)
	b := a
	c := a[0:3]
	a[0] = -1

	fmt.Println(a) //[-1 0 0 0]
	fmt.Println(b) //[-1 0 0 0]
	fmt.Println(c) //[-1 0 0]
}

slice 深拷贝(copy 函数)
将第二个 slice 里的元素拷贝到第一个 slice 里,拷贝的长度为两个 slice 中长度较小的长度值(注意是 len 不是 cap)

package main

import (
	"fmt"
)

func main() {
	a := []int{1, 2, 3}
	e := make([]int, 10, 10)

	//将第二个 slice 里的元素拷贝到第一个 slice 里,拷贝的长度为两个 slice 中长度较小的长度值(注意是 len 不是 cap)
	copy(e, a)

	fmt.Println(e) //[1 2 3 0 0 0 0 0 0 0]

	a[0] = -1
	fmt.Println(e) //[1 2 3 0 0 0 0 0 0 0] a 的值改变后 e 没有改变, copy 是深拷贝
}

map

map 是无序的,每次打印出来的 map 顺序不一定一样,它不能通过 index 获取,而必须通过 key 获取
map 的长度是不固定的,也就是和 slice 一样,也是一种引用类型
内置的 len 函数同样适用于 map,返回 map 拥有的 key 的数量
map 的值可以很方便的修改,通过 numbers[“one”] = 11 可以很容易的把 key 为 one 的字典值改为 11
map 和其他基本型别不同,它不是 thread-safe ,在多个 go-routine 存取时,必须使用 mutex lock 机制

map 的声明以及初始化

map 的类型可以是可以是 string 及所有完全定义了 == 与 != 操作的类型
map 对象必须要用 make 初始化后才能访问

package main

import (
	"fmt"
)

func main() {
	// 声明一个 key 是字符串, 值为 int 的字典, 这种方式的声明需要在使用之前使用 make 初始化
	var nums map[string]int
	//	nums["xxx"] = 1 // panic: assignment to entry in nil map

	nums = make(map[string]int) //默认初始化为 0(对应 value 类型的 0 值)
	fmt.Println(nums["xx"])     // 0
	nums["xxx"] = 12
	fmt.Println(nums["xxx"]) //12

	//直接用 make 声明并初始化
	cnt := make(map[string]int) //默认初始化为 0
	cnt["xxx"] = 11             //初始化后可以进行访问

	gg := cnt["xxx"]
	ok, value := cnt["xxx"]
	fmt.Println(ok, value) //11 true
	fmt.Println(gg)        //11

}
map 是引用类型

如果两个map同时指向一个底层,那么一个改变,另一个也相应的改变

cnt := make(map[string]int)
cnt["xxx"] = 1
cnt["ggg"] = 2

gel := cnt
cnt["xxx"] = -1

//cnt 和 gel 指向同一个底层对象, cnt 的值改变则 gel 也跟着变化
fmt.Println(cnt) //map[xxx:-1 ggg:2]
fmt.Println(gel) //map[xxx:-1 ggg:2]
delete 操作

delete 一个不存在的元素则什么也不做, 不会引起异常

package main

import (
	"fmt"
)

func main() {
	cnt := make(map[string]int)
	cnt["xxx"] = 1
	cnt["ggg"] = 2

	delete(cnt, "aaa") //delete 一个不存在的元素则什么也不做, 不会引起异常
	fmt.Println(cnt)   //map[xxx:1 ggg:2]

	delete(cnt, "xxx")
	fmt.Println(cnt) //map[ggg:2]

}