这是Go语言学习笔记的第四篇
Go语言学习笔记参考书籍「Go语言圣经」以及Go官方标准库
数组
数组是指一系列同类型元素的集合。Go语言中,数组使用前必须指定长度,数组长度在定义以后就不可以更改。
//数组的声明
var arr1 [2] int
var arr2 [10] int
var arr3 [2][3]int //二维数组
var arr4 [2]*int //指针数组
//数组赋值
arr1[0] = 0
arr1[1] = 1
//指针数组赋值
v0 := 1
v1 := 2
arr4[0] = &v0
arr4[1] = &v1
//上述赋值适应于数组元素较少时,当数组元素较多,可以用for循环来处理
for i:=0; i<2; i++ {
for j:=0; j<3; j++ {
arr3[i][j] = i + j
}
}
//数组初始化
var arr5 = [5]float32{1.0, 2.0, 3.4, 5.6, 7.8}
arr6 := [2]int{0,1}
//[]中的数组可以忽略,编译器会根据元素个数来设置
var arr7 = [...]string{"first name", "second name", "third name"}
可以使用内置函数len(arry)
来获取数组长度,如果想访问数组元素,一般使用数组下标。数组下标从0开始,len(array)-1
表示最后一个元素。除此之外,还可以使用关键字range
:
for i, v := range array {
fmt.Println("Array element[", i, "]=", v)
}
//range 具有两个返回值,第一个返回元素的数组下标,第二个返回元素值
需要特别注意,在Go语言中数组是一个值类型。值类型就是变量在赋值或作为参数传递时会产生copy动作。因此,若函数的参数类型是数组,则函数调用时会发生数据copy,传入函数的其实只是数组的一个副本,也就无法在函数内部更改数组内容。
func modifyArray(arr [5]int) {
for i:=0; i<len(arr); i++ {
arr[i] = i + 1
}
fmt.Println("In modifyArray(), array values: ", arr)
}
func main() {
arr := [5]int{1,2,3,4,5}
modifyArray(arr)
fmt.Println("In main(), array values")
}
程序执行结果为:
In modify Array(), array values: [3 4 5 6 7]
In main(), array values: [1 2 3 4 5]
那么问题来了,如果想在函数内部修改数组内的数据怎么办呢?这时候则使用数组切片。
数组切片
数组切片初看就像一个指向数组的指针,实际上它也有自己的数据结构,数组切片抽象为3个变量:
- 一个指向原生数组的指针
- 数组切片中的元素个数
- 数组切片已分配的存储空间
基于数组,数组切片添加了一系列管理功能,可以随时动态扩展存储空间,并且可以被随意传递而不会导致管理的元素被重复复制。
创建数组切片
创建数组切片有两种方式,基于数组(数组切片)和直接创建(使用内置函数make()
)。我们通过例子来看两种创建方式:
arr := [10]int{1,2,3,4,5,6,7,8,9,10}
var slice0 [] = arr[:5]//从数组创建
//创建个数为5,初始值为0的切片
var slice1 := make([]int, 5)
//创建个数为5,初始值为0,并预留10个存储空间的切片
var slice2 := make([]int, 5, 10)
//直接创建5个元素切片
var slice3 := []int{1,2,3,4,5}
从上面看出,Go语言使用array[first:last]方式来生成数组切片,例如下面几种都是合法的:
//基于arr的所有元素创建数组切片
var mySlice = arr[:]
//基于arr的前5个元素创建
var mySlice = arr[:5]
//基于从第5个开始创建后面所有的数组切片
var mySlice = arr[5:]
//创建从第2个到第5个的数组切片
var mySlice = arr[2:5]
//甚至创建的数组切片元素可以超过原数组元素个数,只要不超过原数组的存储能力(cap()返回的值),超出部分会填0
var mySlice = slice2[2:7] //slice2数组有5个元素,储存能力为10
动态扩展元素
数组的所有操作同样适应于数组切片,例如len()
获取元素个数,range()
快速遍历:
数组切片还有一个重要的功能就是可动态增减元素。数组切片支持内置的cap()
函数,返回数组切片分配空间的大小。看个例子:
func main() {
mySlice := make([]int, 5, 10)
fmt.Println("len(mySlice): ", len(mySlice))
fmt.Println("cap(mySlice): ", cap(mySlice))
//往mySlice元素后追加新元素,形成新数组切片
mySlice = append(mySlice, 1,2,3)
mySlice2 := []int{8,9,10}
mySlice = append(mySlice, mySlice2...)
/* 上面这行代码mySlice2后面的三个点如果缺少,会编译错误。*/
/* 原因是append的函数定义从第二个参数起,都是可增加参数。*/
/* mySlice的元素类型是init, 直接传递的mySlice2是数组切片,类型错误。*/
/* 加上省略号即三个点相当于把mySlice2包含的所有元素打散后传入 */
/* 相当于 mySlice = append(mySlice, 8,9,10) */
fmt.Println("mySlice: ", mySlice)
/*上面追加的元素超过了原来的10个元素容量,此时数组切片会重新自动处理存储空间不足,自动分配一块足够大的内存*/
}
内容复制
slice1 := []int{1,2,3,4,5}
slice2 := []int{5,4,3}
copy(slice2, slice1) //只复制slice1的前三个元素
copy(slice1, slice2) //只复制slice2的3个元素到slice1的前三个位置
数组切片支持内置函数copy()
, 用于将内容在数组切片之间复制。上面的例子表明:如果两个数组切片不一样大,就会按照其中较小的数组切片的元素个数进行复制。
map
map是一堆键值对的未排序集合。先看一个例子:
//定义一个struct
type bookInfo struct {
ID string
Name string
Price string
}
func main() {
var bookDB map[string] bookInfo
bookDB = make(map[string] bookInfo)
//插入数据
bookDB["1"] = bookInfo{"1", "Harry Potter", "$20"}
bookDB["123"] = bookInfo{"123", "Steve Jobs:A Biography","$12"}
//在map中查找
book, ok := bookDB["1234"]
if ok {
fmt.Println("find the book: ", book.Name, "the price is: ", book.Price)
} else {
fmt.Println("sorry, didn't find the book.")
}
}
上面例子涉及到了map的声明、初始化、赋值,查找。
变量声明
第8行声明了一个map, 其中变量名为bookDB, map的键类型为string, 存放的值类型为bookInfo.
创建
用内置函数make()
创建一个map,像第9行代码。也可以在创建的时候指定map的存储能力:
bookDB = make(map[string]bookInfo, 100)
, 同样也可以在创建map的时候初始化:
bookDB = map[string]bookInfo{"1": bookInfo{"1", "Harry Potter", "$20"}}
删除元素
使用内置函数delete()
来删除map中的元素。例如:delete(bookDB, "123")
,如果“123”不存在,则什么都不会发生,如果存在,则会删除key为“123”的value。
查找元素
go语言中查找map中值非常方便,代码如下:
value, ok := bookInfo["123"]
if ok {
//找到了,处理找到的value
}
本文中的代码均整合上传至github, 请参考源文件
网友评论