接下来我们介绍GO语言的数组,切片和映射(map),他们统称为容器。
一、数组(array):
数组是一种固定长度、存储相同类型元素的数据结构。在Go语言中,数组的长度是其类型的一部分,因此不同长度的数组被视为不同类型。
package main
import "fmt"
func main() {
var a [5]int
a[4] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD)
}
数组的特点:
- 定义数组:可以通过指定元素类型和长度来定义数组。例如,
var arr [5]int定义了一个长度为5的整数数组。 - 初始化数组:可以在定义数组时或者后续操作中初始化数组元素。例如,
arr := [3]int{1, 2, 3}定义了一个包含3个元素的整数数组,并初始化为1、2、3。 - 访问数组元素:可以使用索引操作符
[]来访问数组元素。数组的索引从0开始,最大索引为数组长度减1。例如,arr[0]表示数组中的第一个元素。 - 数组长度:可以使用内置函数
len()获取数组的长度。例如,length := len(arr)将返回数组arr的长度。 - 数组遍历:可以使用循环语句(如
for循环)来遍历数组元素。通过循环索引或者直接遍历数组,可以依次访问数组中的每个元素。 - 多维数组:Go语言也支持多维数组,即具有多个维度的数组。可以通过嵌套数组来实现多维数组的定义和访问。
- 注意:Go语言中,数组是值类型,传递数组给函数时会进行值拷贝。如果需要在函数中修改数组,可以考虑使用切片类型。
在其他编程语言中也有数组这一数据类型,以下是GO语言和其他语言的区别:
-
- 长度固定:Go语言中的数组长度是固定的,在定义数组时需要指定长度。这意味着不能动态改变数组的大小。相比之下,一些编程语言(如Python)的数组可以动态调整大小。
import numpy as np
# 创建一个一维整数数组
arr = np.array([1, 2, 3, 4, 5])
# 打印数组
print(arr) # 输出:[1 2 3 4 5]
# 访问数组元素
print(arr[0]) # 输出:1
print(arr[2]) # 输出:3
# 修改数组元素
arr[1] = 10
print(arr) # 输出:[ 1 10 3 4 5]
# 添加新元素到数组末尾
arr = np.append(arr, 6)
print(arr) # 输出:[ 1 10 3 4 5 6]
# 删除指定索引处的元素
arr = np.delete(arr, 2)
print(arr) # 输出:[ 1 10 4 5 6]
# 获取数组长度
length = len(arr)
print(length) # 输出:5
# 遍历数组元素
for num in arr:
print(num) # 依次输出数组中的每个元素
-
- 值类型:Go语言中的数组是值类型。当将一个数组赋值给另一个数组或者将数组作为函数参数传递时,会进行值拷贝。这意味着对一个数组的修改不会影响到其他数组。相比之下,一些编程语言(如Java)的数组是引用类型,对数组的修改会影响到其他引用该数组的变量。
-
- 数组切片:Go语言提供了更为灵活的数组抽象,称为数组切片(slice)。数组切片是对底层数组的引用,并可以动态调整大小。数组切片可以根据需要进行追加、删除和修改等操作,因此在Go语言中常常使用数组切片来代替原始的数组。
-
- 多维数组:Go语言支持多维数组,即具有多个维度的数组。可以通过嵌套数组的方式定义多维数组,例如
var arr [3][3]int表示一个3x3的二维整数数组。
- 多维数组:Go语言支持多维数组,即具有多个维度的数组。可以通过嵌套数组的方式定义多维数组,例如
-
- 遍历方式:Go语言中的数组可以使用循环语句遍历,也可以使用range关键字来遍历数组元素。range返回索引和对应的值,更加方便遍历和操作数组。
结论:总体来说,Go语言的数组相对简单,并且在性能和内存上有优势。然而,由于数组长度的限制和值拷贝的特性,Go语言的数组在某些场景下可能不够灵活,这时可以考虑使用数组切片作为替代选择。
二、切片(slice)
先看代码:
package main
import "fmt"
func main() {
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) // [a b c d e f]
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e f]
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
good := []string{"g", "o", "o", "d"}
fmt.Println(good) // [g o o d]
}
在 Go 语言中,切片(slice)是对数组(array)的一个引用,它提供了一种方便且灵活的方式来操作和管理数组。切片可以动态增长和收缩,相比固定长度的数组更加灵活。
Go 语言切片的基本使用方法:
-
- 创建切片:可以通过对数组或其他切片进行切割操作来创建新的切片。例如:
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:3] // 创建从索引1到2的切片,包含元素:[2, 3]
-
- 切片表达式:切片表达式使用
start:end的方式来指定切片的范围,其中start表示起始索引(包括),end表示结束索引(不包括)。如果忽略start或end,则表示从开始或结束位置截取到边界。例如:
- 切片表达式:切片表达式使用
slice := arr[:] // 创建包含整个数组的切片
slice := arr[1:] // 创建从索引1到末尾的切片,包含元素:[2, 3, 4, 5]
slice := arr[:3] // 创建从开头到索引2的切片,包含元素:[1, 2, 3]
slice := arr[1:3:4] // 创建从索引1到索引2的切片,容量为3,包含元素:[2, 3]
-
- 修改元素:可以通过索引来修改切片中的元素。切片是对数组的引用,改变切片会同时改变底层数组的对应元素。例如:
slice[0] = 10 // 将切片中的第一个元素修改为10,同时也修改了原始数组的第二个元素
-
- 动态增长:由于切片的长度是可变的,可以使用内置的
append()函数向切片中添加元素。它会根据需要自动调整底层数组的容量。例如:
- 动态增长:由于切片的长度是可变的,可以使用内置的
slice = append(slice, 6) // 向切片末尾添加元素6
-
- 切片长度和容量:切片有两个重要的属性:长度和容量。长度表示切片中的元素个数,容量表示切片底层数组中可容纳的元素个数。可以使用内置的
len()和cap()函数获取切片的长度和容量。例如:
- 切片长度和容量:切片有两个重要的属性:长度和容量。长度表示切片中的元素个数,容量表示切片底层数组中可容纳的元素个数。可以使用内置的
length := len(slice) // 获取切片的长度
capacity := cap(slice) // 获取切片的容量
-
- 遍历切片:可以使用循环结构如
for循环来遍历切片中的元素。例如:
- 遍历切片:可以使用循环结构如
for _, num := range slice { // 遍历切片中的每个元素
fmt.Println(num)
}
注意:切片是引用类型,所以将切片传递给函数时,对切片的修改会影响原始切片和底层数组。
三、映射
package main
import "fmt"
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
fmt.Println(len(m)) // 2
fmt.Println(m["one"]) // 1
fmt.Println(m["unknow"]) // 0
r, ok := m["unknow"]
fmt.Println(r, ok) // 0 false
delete(m, "one")
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3)
}
···
在 Go 语言中,映射(Map)是一种无序的键值对集合。映射提供了一种方便的方式来存储和检索数据,类似于其他编程语言中的字典、哈希表或关联数组。
-
- 创建映射:可以使用内置的
make()函数创建一个空的映射。例如:
- 创建映射:可以使用内置的
m := make(map[keyType]valueType)
其中,keyType 是键的类型,valueType 是值的类型。
-
- 添加键值对:使用赋值操作符
=可以向映射中添加或更新键值对。例如:
- 添加键值对:使用赋值操作符
m[key] = value
这将把 key 和 value 成对地添加到映射中。
-
- 获取值:使用键作为下标可以获取映射中对应的值。例如:
value := m[key]
如果映射中不存在该键,则返回 value 类型的零值。
-
- 删除键值对:使用内置的
delete()函数可以从映射中删除指定的键值对。例如:
- 删除键值对:使用内置的
delete(m, key)
如果映射中不存在该键,delete() 函数不会产生任何影响。
-
- 判断键是否存在:可以使用以下形式来判断映射中是否存在某个键:
value, ok := m[key]
其中,value 是映射中 key 对应的值,而 ok 是一个布尔值,表示是否存在该键。
-
- 遍历映射:可以使用
range关键字和for循环来遍历映射中的所有键值对。例如:
- 遍历映射:可以使用
for key, value := range m {
// 使用 key 和 value 进行相应的操作
}
在每次循环迭代中,key 和 value 将分别被赋值为映射中的键和值。