Go从入门到精通——数组、切片和映射
数组、切片和映射
本章介绍如下内容:
- 使用数组
- 使用切片
- 在切片中添加和删除元素
- 使用映射
1.1 使用数组
数组是一个数据集合,在编程中它通常按逻辑对数据进行分组。数组也是基本的编程构件,常用于存储一系列用数字做索引的数据。
在 Go 语言中,要创建数组,可声明一个数组变量,并制定其长度和数据类型。
var cheeses [2]string
-
- 使用关子健 var 声明一个名为 cheeses 的变量;
- 将一个长度为 2 的数组赋给这个变量;
- 这个数组的类型为字符串。
声明变量后,便可将字符串赋给数组的元素了。
cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne"
变量名后面的方括号和数字指定要将值赋给数组的哪个元素。索引从 0 而不是 1 开始,因此要访问数组的第一个元素,需要使用索引 0;要访问数组的第二个元素,需要使用索引 1,依次类推。
要打印数组的元素的值,可结合使用变量名和索引值:
fmt.Println(cheeses[0]) fmt.Println(cheeses[1])
另外,要打印数组的所有元素,可使用变量本身。
fmt.Println(cheeses)
程序清单:声明一个数组并给其赋值,再将其打印到终端。
package main import "fmt" func main() { var cheeses [2]string cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne" fmt.Println(cheeses[0]) fmt.Println(cheeses[1]) fmt.Println(cheeses) }
注意:数组声明长度后,就不能再给它添加元素了。如果在数组 cheeses 的索引2处添加一个值,会怎么样呢?
package main import "fmt" func main() { var cheeses [2]string cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne" fmt.Println(cheeses[0]) fmt.Println(cheeses[1]) fmt.Println(cheeses) cheeses[2] = "Camembert" }
[root@iZj6cikc0tkurv3slmie8jZ go-testfiles]# go run 声明数组并给它赋值.go # command-line-arguments ./声明数组并给它赋值.go:13:9: invalid array index 2 (out of bounds for 2-element array)
由于数组 cheeses 声明为只包含两个元素,无法给第 3 个元素赋值,因此这将会导致编译阶段错误。
1.2 使用切片
在 Go 语言中,数组是一个重要构件,但使用切片的情况更多。切片是底层数组中一个连续片段,通过它可以访问该数组中一系列带编号的元素。因此,切片可以顺序访问数组的特定部分。
为什么要用切片呢?为何不直接使用数组呢?
在 Go 语言中,使用数组存在一定的局限性。采用前面的数组 cheeses 表明方式,比如无法在数组中添加元素;然而切片比数组更灵活,你可以在切片中添加和删除元素,还可复制切片中的元素。可将切片视为轻量级数组包装器,它既保留了数组的完整性,又比数组使用起来更容易。
要声明一个长度为 2 的空切片,可使用如下语法:
var cheeses = make([]string, 2)
- 使用关键字 var 声明一个名为 cheeses 的变量。
- 在等号右边,使用 Go 内置函数 make 创建一个切片,其中第一个参数为数据类型,而第二个参数为长度。在这里,创建的切片包含两个字符串元素。
- 将切片赋给变量 cheeses。
创建切片后,可像给数组赋值一样给切片赋值:
cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne"
要打印切片的值,方法与打印数组一样:
fmt.Println(cheeses[0]) fmt.Println(cheeses[1])
到目前为止,切片类似于数组,但不同于数组的是,切片中可以添加和删除元素。
1.2.1 在切片中添加元素
Go 语言提供了内置函数 append,让你能够增大切片的长度。
cheeses := append(cheeses, "Camembert") fmt.Println(cheeses[2])
append 会在必要时调整切片的长度,但它对程序员隐藏了这种复杂性。在这里,将切片的长度 2 调整到3,并将值 "Camembert" 赋给了新创建的元素(其索引为 2 )。在编程接口方面,你只需要使用新创建的索引来引用这个元素即可。这样,只需要一行代码,就调整了切片的长度,并给新元素赋值了。
程序清单:演示了如何在切片中添加元素
package main import ( "fmt" ) func main() { var cheeses = make([]string, 2) cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne" cheeses = append(cheeses, "Camembert") fmt.Println(cheeses[2]) fmt.Println(cheeses) }
函数 append 也是一个不定参数函数。这就意味着它的参数数量是可变的,使用函数 append 可在切片末尾添加很多值。
程序清单:在切片末尾添加多个元素
package main import "fmt" func main() { var cheeses = make([]string, 2) cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne" fmt.Println(cheeses) cheeses = append(cheeses, "Camembert", "Reblochon", "Picodon") fmt.Println(cheeses) }
1.2.2 从切片中删除元素
要从切片中删除元素,也可使用内置函数 append。Go 语言并没有对删除切片元素提供专用的语法或接口,需要使用切片本身的特性来删除元素。
程序清单:从切片中删除元素1.go
package main import "fmt" func main() { var cheeses = make([]string, 3) cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne" cheeses[2] = "Camembert" fmt.Printf("切片长度: %v\n", len(cheeses)) fmt.Println(cheeses) cheeses = append(cheeses[:1], cheeses[1+1:]...) fmt.Printf("切片长度: %v\n", len(cheeses)) fmt.Println(cheeses) }
程序清单:从切片中删除元素2.go
package main import "fmt" func main() { var cheeses = make([]string, 3) cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne" cheeses[2] = "Camembert" //指定删除位置 index := 1 fmt.Println(cheeses[:index], cheeses[index+1:]) // 删除元素节点 cheeses = append(cheeses[:index], cheeses[index+1:]...) }
1.2.3 复制切片中的元素
要复制切片的全部或部分元素,可使用内置函数 copy。在复制切片中的元素前,必须再声明一个类型与该切片相同的切片。
程序清单:将一个切片的元素复制到另一个切片中
package main import "fmt" func main() { var cheeses = make([]string, 2) cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne" var smellyCheeses = make([]string, 2) copy(smellyCheeses, cheeses) fmt.Println(smellyCheeses) }
程序清单:将一个切片的部分元素复制到另一个切片中
package main import "fmt" func main() { var cheeses = make([]string, 2) cheeses[0] = "Mariolles" cheeses[1] = "Epoisses de Bourgogne" var smellyCheeses = make([]string, 2) copy(smellyCheeses, cheeses[1:]) fmt.Println(smellyCheeses) }
1.3 使用映射
数组和切片是可通过索引值访问的元素集合,而映射是通过键来访问的无须元素编组。大多数编程语言都支持数组;在其他编程语言中,映射也被称为关联数组、字典或散列。映射在信息查找方面的效率非常高,因为可直接通过键来检索数据。简单地说,映射可视为键-值对集合。
创建映射语法:
var players = make(map[string]int)
- 关键字 var 声明了一个名为 players 的变量。
- 在等号右边,使用 Go 语言内置函数 make 创建了一个映射,其键的类型为字符串,而值的类型为整数。
- 将这个空映射赋给了变量 players。
现在可在这个空映射中添加键-值对了:
players["cook"] = 32 players["bairstow"] = 27 players["stokes"] = 26
变量名后面的方括号为键,而等号右边是要赋值给键的整数值。
要打印映射中的特定键对应的值,可使用这个键来获取相应的值:
fmt.Println(players["cook"]) fmt.Println(players["stokes"])
和数组和切片一样,要打印映射中所有键-值对,可使用变量名本身:
fmt.Println(players) map[cook:32 bairstow:27 stockes:26]
程序清单:演示了如何声明和创建映射以及如何在映射中添加元素
package main import "fmt" func main() { var players = make(map[string]int) players["cook"] = 32 players["bairstow"] = 27 players["stokes"] = 26 fmt.Println(players["cook"]) fmt.Println(players["bairstow"]) }
可在映射中动态地添加元素,而无须调整映射长度。这时 Go 语言更像 Ruby 和 Python 等动态语言,而不像 C 语言的方面之一。
从映射中删除元素
要从映射中删除元素,可使用内置函数 delete。
delete(players,"cook")
程序清单:从映射中删除元素
package main import ( "fmt" ) func main() { var players = make(map[string]int) players["cook"] = 32 players["bairstow"] = 27 players["stokes"] = 26 fmt.Println(players) delete(players, "cook") fmt.Println(players) }
1.4 问与答
问:该使用数组还是切片?
答:除非确定必须使用数组,否则请使用切片。切片能够让你轻松地添加和删除元素,还无须处理内存分配问题。
问:没有从切片中删除元素的内置函数吗?
答:不能将 delete 用于切片。没有专门用于从切片中删除元素的函数,但可使用内置函数 append 来完成这种任务,你还可创建子切片。
问:需要指定映射的长度吗?
答:不需要。使用内置函数 make 创建映射时,可使用第二参数,但这个参数只是容量提示,而非硬性规定。映射可根据要存储的元素数量自动增大,因此没有必须要指定长度。