数组是编程语言中最常用的数据结构,Go语言中声明数组的方式如下:
var arr [3]int
var ptr_arr [10]*float64
var multi_arr [3][5]int
注意,数组长度在定义后就不可在更改,在声明时长度可以为一个常量或者一个常量表达式。
获取数组的长度使用内置函数len()
来获取。
元素访问
使用数组下标访问,例如arr[0]
获取数组中第一个元素,与C语言类似。
数组赋值
var arr [5]int = [5]int{1, 2, 3, 4, 5}
数组遍历
最基础的类似C语言遍历方式。
var arr [5]int = [5]int{1, 2, 3, 4, 5}
for i :=0; i < len(arr); i++ {
fmt.Println(arr[i]);
}
Go语言提供了一个关键字range
,用于遍历容器中的元素。
for i, v := range arr {
fmt.Println(i, v);
}
注意,在Go语言中数组是一个值类型,所有的值类型变量在赋值和作为参数传递时将产生一次复制动作。不像C语言数组的默认的是第一个元素的指针。
基于数组
var myArray [5]int = [5]int{1, 2, 3, 4, 5} // 定义数组
var mySlice []int = myArray[:3]
fmt.Println(mySlice) // [1, 2, 3]
支持myArray[first:last]
方式来生成一个数组切片。
基于数组所有元素创建数组切片:mySlice = myArray[:]
。
基于数组前3个元素创建数组切片:mySlice = myArray[:3]
。
基于从第5个元素开始所有元素创建数组切片:mySlice = myArray[5:]
。
直接创建
var mySlice []int // 声明一个数组切片
mySlice := make([]int, 5) // 使用内置函数make()创建数组切片
用内置函数make()
创建一个初始元素个数为5的数组切片,用法如下,
元素初始值为0:mySlice := make([]int, 5)
。
元素初始值为0,并预留10个元素的存储空间:mySlice := make([]int, 5, 10)
。
直接创建并初始化:mySlice := []int{1, 2, 3, 4 ,5}
。
基于数组切片创建
mySlice := []int{1, 2, 3, 4, 5}
newSlice := mySlice[:3]
元素遍历同数组的遍历方式。
数组切片支持内置cap()
和len()
函数。
cap()
函数返回的是数组切片分配的空间大小。
len()
函数返回的是数组切片中当前所存储的元素个数。
mySlice := make([]int, 5, 10)
fmt.Println(cap(mySlice), len(mySlice)) // 10 5
如果向已经包含5个元素后面继续增加新增元素,可以使用append()
函数。
mySlice = append(mySlice, 1, 2, 3)
fmt.Println() // [0 0 0 0 0 1 2 3]
也可以将一个数组切片追加到另一个数组切片的末尾,
mySlice2 := []int{1, 2, 3}
mySlice = append(mySlice, mySlice2...) // 后面三个点(省略号)不能省略,否则会编译错误。
// 类似于
mySlice = append(mySlice, 1, 2, 3)
数组切片内容复制使用内置函数copy()
,用于将内容从一个数组切片复制到另一个数组切片。如果两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行复制。
mySlice1 := []int{1, 2, 3, 4, 5}
mySlice2 := []int{7, 8, 9}
copy(mySlice1, mySlice2) // 只会复制mySlice2的3个元素到mySlice1的前3个位置
// mySlice1 输出 [7, 8, 9, 4, 5]
copy(mySlice2, mySlice1) // 只会复制mySlice1的前三个元素到mySlice2中
// mySlice2 输出 [1, 2, 3]
map是一堆键值对的未排序集合。可以理解类似json的数据结构。
map声明
格式:var newMap map[string] int
。
其中,newMap是声明的map变量名,string是键的类型,int是所存放的值类型。
也可以使用内置函数make()
来创建一个map
var myMap map[string] int // 声明一个map
myMap = make(map[string]int, 10) // 指定该map具有初始10 int的存储能力
// 声明一个myMap2变量,并自动推导成map类型
myMap2 := make(map[string]int)
// 声明map并初始化。
var myMap3 = map[string]int {"php":1, "go": 2}
元素赋值
元素赋值就是键和值用下面的方式对应起来即可。
myMap["go"] = 1
注意一点就是,声明的空map不能直接赋值。
var myMap = map[string]int
myMap["go"] = 1 // 编译报错 panic: assignment to entry in nil map
var newMap = map[string]int {"php":1}
newMap["Go"] = 2 // 编译通过
另外,map键可以是任意内置类型或者struct
类型,slice
、function
和包含slice
的struct
类型不可以作为map
键。
dict := map[[]string] int // 编译错误
元素删除
delete()
内置函数,用于删除容器内的元素,无论键是否存在都编译通过,但是nil的map会抛出异常。
var rank = map[string]int{"php": 1, "go": 2, "c": 3}
delete(rank, "php")
fmt.Println(rank) // map[go:2 c:3]
元素查找
要从map中查找一个特定的键,可以以下方式实现,
value, ok := myMap["go"]
if ok {
// 找到了value
}
遍历
同采用range
的数组遍历方式。
var colors = map[string] string {}
colors["red"] = "#ff0000"
colors["green"] = "#00ff00"
for i, v := range colors {
fmt.Println(i, v)
}
判断是否成功找到特定的键,不需要检查取到的值是否为nil,只需查看第二个返回值ok。
判断map是否为空map
在Go语言中。可以用内置len()
判断元素个数。
var dict = map[string] int {} // 声明一个map并初始化为空
fmt.Println(len(dict)) // 输出 0
Map在函数间传递,不是map值拷贝,而是值引用,所以引用map的地方都会改变。
func modify(colors map[string] string) {
colors["red"] = "#f00000"
}
var colors = map[string] string{"red": "#ff0000"}
modify(colors)
fmt.Println(colors) // 输出 map[red:#f00000]
总结一下数组(Array)、数组切片(slice)和Map区别:
数组的长度是固定并且不可以改变的,数组切片(slice)的长度是可变的,而Map的长度类似于数组切片的形式, 简单看一下三者的声明。
var arr [4]int // 数组的声明方式
var mySlice []int // 切片的声明方式
var dict map[string]int // map的声明方式
数组(Array)在函数间传递是按值传递,而数组切片(slice)和Map在函数之间传递是值引用,只有改变Map的元素,原来的map或slice就会跟着改变。
数组(Array)和数组切片(Slice)是不同的类型。切记在函数间传递的时候,注意下参数的类型。
func modify(colors []int) {
// 实现代码
}
func main() {
var color [2]string = {"#000000", "#ffffff"}
modify(color) // 编译错误 cannot use colors (type [2]string) as type []string in argument to modify
}