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 创建映射时,可使用第二参数,但这个参数只是容量提示,而非硬性规定。映射可根据要存储的元素数量自动增大,因此没有必须要指定长度。

posted @ 2021-08-17 11:42  左扬  阅读(191)  评论(0编辑  收藏  举报
levels of contents