数组,大概是每个变成语言都有基础数据结构。

Go的切片类型(slice)提供了一种方便和有效的方法来处理类型化数据序列(数组)。slice类似于其他语言中的数组,但有一些不同寻常的属性。

map可以理解为一个字典。

数组声明

可以使用 [长度]类型{} 来定义,比如 [2]string{}定义一个长度为2的字符串数组

这里的长度必须是一个常量,如果要使用变量去动态生成数组的话,需要使用make,如

make([]string, size) 这里的size是一个变变量,生成size长度的字符串数组

另外需要注意的是, [1]string[2]string 不是用一种类型,长度也是数组类型的一部分

定义数组时可以省略数组的长度,此时会根据大括号{}里面的元素个数推到出数组的长度:

arr := []string{"a", "b", "c", "d", "e"}

这里会自动生成长度为5的字符串数组,适用于所有元素都被初始化的数据

但是如果只有特定元素被初始化的数组,就不合适了:

arr := [5]string{1: "a", 3: "c"}

上述表示数组初始化索引为1的值为a,索引为3的值为c,其他未初始化的为空值(字符串的空值为"")

如果我们不指定 [5]string,那么go就会根据我们定义的最大索引值3 来确定数组的长度为4

数组循环

  • 使用传统的数组循环:
for i := 0; i < len(arr); i++ {
		fmt.Println(arr[i])
}
  • 使用 for range 数组遍历,写法更加简洁
for index, value := range arr {
		fmt.Printf("index = %v, value = %v\n", index, value)
}

切片 Slice

切片的区间是左闭右开,如arr[2:5],选取的索引取数是[2,3,4] 切片的底层是(原)数组,将切片内容修改之后,原数组也会改变

arr := []int{1,2,3,4,5}
sliced := arr[1:3]
// sliced = {2,3}
sliced[0] = 0
// 切片修改后,原数组内容有会改变
// arr = {1, 0, 3, 4, 5}

使用make声明切片

声明一个元素类型为string的切片,长度为5:slice1 := make([]string, 5) 还可以传入一个容量参数:slice2 := make([]string, 4, 8) 这里声明了一个长度为4,容量为8的字符串数组 长度是切片内元素的个数,容量是切片的空间

上面的示例说明,Go 语言在内存上划分了一块容量为 8 的内容空间(容量为 8),但是只有 4 个内存空间才有元素(长度为 4),其他的内存空间处于空闲状态,当通过 append 函数往切片中追加元素的时候,会追加到空闲的内存上,当切片的长度要超过容量的时候,会进行扩容。

除了make,同样可以通过字面量的方式声明: slice1 := []string{"a", "b", "c"}

Append

通过内置的append函数对一个切片进行元素追加,返回新的切片

//追加一个元素
slice2:=append(slice1,"f")
//多加多个元素
slice2:=append(slice1,"f","g")
//追加另一个切片
slice2:=append(slice1,slice...)

切片元素循环

可以使用for range,同array一样

Map映射

map是无序的K-V键值对集合,结构为 map[k]v,k为Key,v为Value key的类型必须支持 ==运算符,以便判断其是或否存在,并保证Key的唯一

Map的声明初始化

使用内置的make函数进行初始化

// 创建的map,key类型为string,value类型为int
nameAgeMap := make(map[string]int)

赋值: nameAgeMap["Mike"] = 10

Map获取和删除

map的操作和数组、切片差不多,都是通过[]操作符,不过切片中的[]是索引,而map的[]是key

Go 语言的 map 可以获取不存在的 K-V 键值对,如果 Key 不存在,返回的 Value 是该类型的零值,比如 int 的零值就是 0。所以很多时候,我们需要先判断 map 中的 Key 是否存在。

如何判断map中是否存在某个值呢

map 的 []操作会返回两个值

  • 对应的Value
  • 标记该Key是否存在,存在则该标记为true
mapper := map[string]int{"Mike": 10, "Lisa": 11}
value, tag := mapper["Mike"]
fmt.Println(value, tag)		// tag 为true
value, tag := mapper["John"]
fmt.Println(value, tag)		// tag 为false

使用delete删除map中的值

delete(mapper, "Mike")

遍历map

使用 for range 十分方便,返回 map的key和value

mapper := map[string]int{"Mike": 10, "Lisa": 11}
for key, value := range mapper {
	fmt.Println(key, value)
}

需要注意的是 map 的遍历是无序的,也就是说你每次遍历,键值对的顺序可能会不一样。如果想按顺序遍历,可以先获取所有的 Key,并对 Key 排序,然后根据排序好的 Key 获取对应的 Value

map的大小

和数组切片不一样的是,map是没有容量的,只有长度,获取长度只需要使用len函数即可: fmt.Println(len(mapper))

string 和 []byte

字符串string也是一个不可变的字节序列,可以直接转为字节切片 []byte

s := "你好golang"
bs := []byte(s)
fmt.Println(bs)
// 同样可以使用[] 操作符来获取指定索引的字节值:
fmt.Println(s[0], s[11])
// 在go语言中,utf8编码下,一个汉字对应三个字节,因此,s虽然只有8个字符,但是长度却是12。

如果我们想把汉字当成一个长度计算,可以使用utf8.RuneCountInString函数