数组声明

朴素的方法

//var arr_name[quality]Type
var arr[4]int

数组内元素赋值

//arr_name[index] = Value
arr[0] = 5

已知数组值时的方法

//第一种:指定长度
//var arr = [len]type{value1, value2, ...}
var arr1 = [5]int{18, 20, 15, 22, 16}
var arr2 = [10]int{1, 1, 1}//除了前三个剩下全部自动赋0
//第二种:不指定长度,长度取决于初始化元素个数
//var arr = [...]type{value1, value2, ...}
var arr = [...]int{18, 20, 15, 22, 16}//[5]int
//第三种:只给特定索引赋值
//var arr = [len]type{key1:value1, key2:value2, ...}
var arr = [5]string{3: "Chris", 4: "Ron"}

多维数组

//var matrix [x_len][y_len]type
var matrix [5][3]int

切片

内部实现

图例
源代码

朴素声明

//var slice_name[]Type
var slice[]int

声明切片和数组的区别仅仅是去掉了中括号中的元素个数!

由已知数组而来

//var slice []type = arr[start: end]
//取arr[start, end)区间里的元素
var slice []type = arr[:]//切片取arr全部元素
var slice []type = arr[:5]//切片取arr[0, 5)
var slice []type = arr[3:]//切片取arr[3, len(arr))

make函数声明

slice := make([]string, 5)

这种方法创建了一个容量和长度都是5的字符串切片.

slice := make([]string, 3, 5)

这种方法创建了一个容量为5长度为3的字符串切片.

append()函数

在Go语言中,为切片“扩充”需要使用append()函数,使用格式如下:

//append(s []T, x ...T)
append(slice, 1)

append()函数本身并不改变原有切片,只是将切片扩容后的结果作为返回值.因此,需要将“扩容”后的结果再次

(即函数返回值)赋值给slice_name,才能真正使slice_name发生改变.

slice = append(slice, value)

append()常见用法如下:

a = append(a, b...) //将切片b的元素追加到切片a之后

b = make([]T, len(a))
copy(b, a)
//复制切片a的元素到新的切片b上

a = append(a[:i], a[i+1:]...)//切除切片a中位于索引i的元素
a = append(a[:i], a[j:]...)//切除切片a中从索引i至j位置的元素

a = append(a, make([]T, j)...)//为切片a扩展j个元素长度

a = append(a[:i], append([]T{x}, a[i:]...)...)//在索引i的位置插入元素x
a = append(a[:i], append(make([]T, j), a[i:]...)...)//在索引i的位置插入长度为j的新切片
a = append(a[:i], append(b, a[i:]...)...)//在索引i的位置插入切片b的所有元素

x, a = a[len(a) - 1], a[: len(a) - 1]//取出位于切片a最末尾的元素x

copy()函数

//func copy(dst, src []T) int
  • 若 len(dst) \geqslant len(src) ,则 src 切片会将其所有 n 个元素赋给 dst 的前 n 个位置
  • 若 len(dst) < len(src) ,则 src 切片会将其前 len(dst) 个元素赋给 dst

返回值是 \min\{len(dst), len(src)\} .

可以利用copy()函数实现对切片的各种操作:

切片扩容:将切片的长度扩充为原来的若干倍

func magnify(s []int, factor int) []int {
	newSlice := make([]int, len(s)*factor)
	copy(newSlice, s)
	s = newSlice
	return s
}

切片间互相插入:将一个切片插入到另一个切片的指定位置

func InsertStringSlice(slice, insertion []string, index int) []string {
	result := make([]string, len(slice)+len(insertion))
	at := copy(result, slice[:index])
	at += copy(result[at:], insertion)
       //借助切片result[at:]和result底层指向同一数组来修改result切片
	copy(result[at:], slice[index:])
	return result
}

删除部分切片:

func RemoveStringSlice(slice []string, start, end int) []string {
	result := make([]string, len(slice)-(end-start))
	at := copy(result, slice[:start])
	copy(result[at:], slice[end:])
        //借助切片result[at:]和result底层指向同一数组来修改result切片
	return result
}

集合

集合初始化

集合(map)可以看作是一类特殊的切片,只不过集合的元素都是由若干“键-值对”数据构成的.

//var map_name = make(map[key_type]value_type)
var studentInfos = make(map[string]string)

key_type表示键的类型,value_type表示值的类型.

注意:不要使用new()来初始化集合!否则会获得一个空引用的指针.

studentInfos["0001"] = "王小红"

集合中元素的赋值和数组类似,只不过中括号中不再是索引,而是键的值.

一次性打印集合结果

package main

import "fmt"

func main() {
	playerInfo := make(map[string]string)
	playerInfo["Doinb"] = "大币老师"
	playerInfo["scout"] = "小飞"
        playerInfo["scout"] = "小飞"
	fmt.Println(playerInfo)
}

打印集合的结果如下

map[Doinb:大币老师 scout:小飞]

\boxed{和python一样,集合可以用来去重} .

用map实现分支结构

map的key不能是数组、切片和结构体类型的,但value可以是任意类型的,甚至可以是函数类型.

示例如下:

package main
import "fmt"

func main() {
	mf := map[int]func() int{
		1: func() int { return 10 },
		2: func() int { return 20 },
		5: func() int { return 50 },
	}
	fmt.Println(mf)
}
//输出map[1:0x10903be0 5:0x10903ba0 2:0x10903bc0]

用切片作为map的值来实现隐函数

mp1 := make(map[int][]int)
mp2 := make(map[int]*[]int)

测试键值对是否存在

当用map[key]的方式来获取对应的值时,若map中不存在key,则会返回value类型的空值,导致无法判断究竟是没有key还是key对应的value就是空值,故需要以下方法:

_, ok := map1[key1] // 如果key1存在则ok == true,否则ok为false

删除键值

delete(map1, key1)

即使key1不存在,该操作也不会产生错误.

len()函数

数组/指向数组的指针/切片/集合均可作为len()函数的参数,返回参数的元素个数.

for-range结构

除了for循环外,Go语言还提供了range关键字,与for结合,也可以实现循环遍历.(遍历集合非常好用)

/*
for index, value := range variable {
    // 循环体
}
*/
for key, value := range studentInfos {
    fmt.Println("学号:", key, "姓名:", value)
}

其中,index表示索引或键的值;value表示元素的值;variable表示数组、切片或集合变量;由大括号包裹的部分

是循环体,可以使用index和value变量.

示例:

package main

import "fmt"

func main() {
	playerInfo := make(map[string]string)
	playerInfo["Doinb"] = "大币老师"
	playerInfo["scout"] = "小飞"
	for id, nickname := range playerInfo {
		fmt.Println("id:", id, "外号:", nickname)
	}
}

输出:

id: Doinb 外号: 大币老师
id: scout 外号: 小飞

\boxed{这种结构适用于集合/切片/数组.}