听峰问雨 听峰问雨
首页
导航站
  • 编程语言

    • Python
  • 数据结构与算法
  • 设计模式
  • UVA
  • LeetCode
  • 《Go语言实战》
  • 《Go Web编程》
  • 《算法精粹 经典计算机科学问题的Python实现》
  • 学习
  • 博客搭建
  • 本站

    • 分类
    • 标签
    • 归档
  • 我的

    • 收藏
    • 关于
GitHub (opens new window)

zfprotectors

默默学习er
首页
导航站
  • 编程语言

    • Python
  • 数据结构与算法
  • 设计模式
  • UVA
  • LeetCode
  • 《Go语言实战》
  • 《Go Web编程》
  • 《算法精粹 经典计算机科学问题的Python实现》
  • 学习
  • 博客搭建
  • 本站

    • 分类
    • 标签
    • 归档
  • 我的

    • 收藏
    • 关于
GitHub (opens new window)
  • 《Go语言实战》

    • Go语言的介绍
    • 快速开始一个Go程序-RSS匹配器
    • 打包和工具链
    • 数组,切片和映射
      • 数组
        • 内部实现
        • 声明和初始化
        • 使用
        • 多维数组
        • 在函数间传递数组
      • 切片
        • 内部实现
        • 创建和初始化
        • 使用
        • 多维切片
        • 在函数间使用切片
      • 映射
        • 内部实现
        • 创建和初始化
        • 使用
        • 在函数间使用映射
    • Go语言的类型系统
    • 并发
  • 《Go Web编程》

  • 《算法精粹 经典计算机科学问题的Python实现》

  • 读书笔记
  • 《Go语言实战》
zfprotectors
2022-05-26
目录

数组,切片和映射

# 数组

# 内部实现

数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连 续块。数组存储的类型可以是内置类型,如整型或者字符串,也可以是某种结构类型。

# 声明和初始化

  • 方法一:普通方式 声明数组时需要指定内部存储的数据的类型,以及需要存储的元素的数量,这个数量也称为数组的长度。
var array [5]int
1

一旦声明,数组里存储的数据类型和数组长度就都不能改变了。如果需要存储更多的元素,就需要先创建一个更长的数组,再把原来数组里的值复制到新数组里。

当数组初始化时,数组内每个元素都初始化为对应类型的零值。

  • 方法二:使用数组字面量 这是快速创建数组并初始化的方式。数组字面量允许声明数组里元素的数量同时指定每个元素的值
array := [5]int{10,20,30,40,50}
1
  • 方法三:...替代数组的长度 Go 语言会根据初始化时数组元素的数量来确定该数组的长度
// 容量由初始化值的数量决定
array := [...]int{10, 20, 30, 40, 50}
1
2
  • 方法四:声明数组并指定特定元素的值
array := [5]int{1: 10, 2: 20}
1

# 使用

  • 要访问数组里某个单独元素,使用[]运算符
// 声明一个包含 5 个元素的整型数组
// 用具体值初始为每个元素
array := [5]int{10, 20, 30, 40, 50}
// 修改索引为 2 的元素的值 
array[2] = 35
1
2
3
4
5
  • 使用*运算符就可以访问元素指针所指向的值
// 声明包含 5 个元素的指向整数的数组
// 用整型指针初始化索引为 0 和 1 的数组元素
array := [5]*int{0: new(int), 1: new(int)}
// 为索引为0和1的元素赋值 
*array[0] = 10 
*array[1] = 20
1
2
3
4
5
6
  • 数组间赋值
var array1 [5]string
array2 := [5]string{"Red", "Blue", "Green", "Yellow", "Pink"}
array1 = array2
1
2
3

只有类型(包括数组长度和每个元素的类型)相同的数组,才能互相赋值

  • 数组指针复制,只会复制指针的值,不会复制指针所指向的值。

# 多维数组

// 声明一个二维整型数组,两个维度分别存储 4 个元素和 2 个元素
var array [4][2]int
// 使用数组字面量来声明并初始化一个二维整型数组
array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
// 声明并初始化外层数组中索引为 1 个和 3 的元素 
array := [4][2]int{1: {20, 21}, 3: {40, 41}}
// 声明并初始化外层数组和内层数组的单个元素 
array := [4][2]int{1: {0: 20}, 3: {1: 41}}

// 访问
// 设置每个元素的整型值 array[0][0] = 10
 
array[0][1] = 20
array[1][0] = 30
array[1][1] = 40

// 将 array1 的索引为 1 的维度复制到一个同类型的新数组里 
var array3 [2]int = array1[1]
// 将外层数组的索引为 1、内层数组的索引为 0 的整型值复制到新的整型变量里 
var value int = array1[1][0]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 在函数间传递数组

在函数之间传递变量时,总是以值传递的方式进行传递的。因此需要使用指针来传递大数组

//分配一个需要8 MB的数组
var array [1e6]int
// 将数组的地址传递给函数
foo foo(&array)
// 函数 foo 接受一个指向 100 万个整型值的数组的指针
func foo(array *[1e6]int) {
... }
1
2
3
4
5
6
7

# 切片

切片是一种数据结构,这种数据结构便于使用和管理数据集合。

切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的大小。

因为切片的底层内存也是在连续块中分配的,所以切片还能获得索引、迭代以及为垃圾回收优化的好处。

# 内部实现

切片有3个字段的数据结构:

  • 指向底层数组的指针
  • 切片访问的元素个数(长度)
  • 切片允许增长到的元素个数(容量) !

# 创建和初始化

  • make和切片字面量
// 创建一个字符串切片,其长度和容量都是 5 个元素 
slice := make([]string, 5)

// 创建一个整型切片,其长度为3个元素,容量为5个元素,长度要小等于容量
slice := make([]int, 3, 5)

// 创建字符串切片,其长度和容量都是 5 个元素
slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}
// 创建一个整型切片,其长度和容量都是 3 个元素 
slice := []int{10, 20, 30}

// 创建字符串切片,使用空字符串初始化第 100 个元素 
slice := []string{99: ""}
1
2
3
4
5
6
7
8
9
10
11
12
13

如果在[]运算符里指定了一个值,那么创建的就是数组而不是切片。只有不指定值的时候,才会创建切片。

array := [3]int{10, 20, 30}
// 创建长度和容量都是 3 的整型切片
slice := []int{10, 20, 30}
1
2
3
  • nil和空切片 只要在声明时不做任何初始化,就会创建一个 nil 切片
// 创建 nil 整型切片
var slice []int

// 使用 make 创建空的整型切片
slice := make([]int, 0)
// 使用切片字面量创建空的整型切片 
slice := []int{}
1
2
3
4
5
6
7

# 使用

  • 赋值和切片
// 创建一个整型切片,其容量和长度都是 5 个元素
slice := []int{10, 20, 30, 40, 50}
// 改变索引为 1 的元素的值
slice[1] = 25

// 创建一个新切片,其长度为 2 个元素,容量为 4 个元素
newSlice := slice[1:3]
1
2
3
4
5
6
7

切片的本质就是把底层数组切除一部分,故而称为切片。若切片从同一个底层数组切除的话,则两个切片共享同一个底层数组,即如果一个切片改变了底层数组的共享部分,另一个切片也会受到影响。

提示

对底层数组容量是k的切片slice[i:j]来说, 长度:j-i 容量:k-i

切片只能访问到其长度内的元素。试图访问超出其长度的元素将会导致语言运行时异常。

  • 切片增长。

相对于数组而言,使用切片的一个好处是,可以按需增加切片的容量。Go 语言内置的 append 函数会处理增加长度时的所有操作细节。

// 创建一个整型切片,其长度和容量都是 5 个元素
slice := []int{10, 20, 30, 40, 50}
// 创建一个新切片,其长度为 2 个元素,容量为 4 个元素
newSlice := slice[1:3]
// 使用原有的容量来分配一个新元素,将新元素赋值为 60
newSlice = append(newSlice, 60)
1
2
3
4
5
6

如果切片的底层数组没有足够的可用容量,append 函数会创建一个新的底层数组,将被引用的现有的值复制到新数组里,再追加新的值。

  • 创建切片时的3个索引

第三个索引可以用来控制新切片的容量。其目的并不是要增加容量,而是要限制容量。

source := []string{"Apple", "Orange", "Plum", "Banana", "Grape"}
slice := source[2:3:4]
1
2

第3个索引值为容量的索引值

  • 迭代切片
slice := []int{10, 20, 30, 40}
 
// 迭代每一个元素,并显示其值
for index, value := range slice {
    fmt.Printf("Index: %d Value: %d\n", index, value)
}
1
2
3
4
5
6

当迭代切片时,关键字 range 会返回两个值。第一个值是当前迭代到的索引位置,第二个值是该位置对应元素值的一份副本。

# 多维切片

// 创建一个整型切片的切片
slice := [][]int{{10}, {100, 200}}
1
2

# 在函数间使用切片

在函数间传递切片就是要在函数间以值的方式传递切片。

# 映射

映射是一种数据结构,用于存储一系列无序的键值对集合。

映射里基于键来存储值。映射能够基于键快速检索数据。键就像索引一样,指向与该键关联的值。

# 内部实现

映射是一个集合,可以使用类似处理数组和切片的方式迭代映射中的元素。

映射是无序的集合,意味着没有办法预测键值对被返回的顺序。无序的原因是映射的实现使用了散列表。

# 创建和初始化

// 创建一个映射,键的类型是 string,值的类型是 int
dict := make(map[string]int)

// 创建一个映射,键和值的类型都是 string,使用两个键值对初始化映射
dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
1
2
3
4
5

映射的键可以是任何值。这个值的类型可以是内置的类型,也可以是结构类型,只要这个值可以使用==运算符做比较

# 使用

// 创建一个空映射,用来存储颜色以及颜色对应的十六进制代码
colors := map[string]string{}
// 将 Red 的代码加入到映射
colors["Red"] = "#da1337"

// 获取键 Blue 对应的值
value, exists := colors["Blue"]
// 这个键存在吗? 
if exists {
    fmt.Println(value)
}

// 创建一个映射,存储颜色以及颜色对应的十六进制代码 
colors := map[string]string{
    "AliceBlue":   "#f0f8ff",
    "Coral":       "#ff7F50",
    "DarkGray":    "#a9a9a9",
    "ForestGreen": "#228b22",
}
// 显示映射里的所有颜色
for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value) 
}

// 删除键为 Coral 的键值对 
delete(colors, "Coral")
// 显示映射里的所有颜色
for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

nil 映射不能用于存储键值对。

# 在函数间使用映射

在函数间传递映射时是进行值传递。

编辑 (opens new window)
#Go
上次更新: 2022/06/10, 08:41:22
打包和工具链
Go语言的类型系统

← 打包和工具链 Go语言的类型系统→

最近更新
01
LeetCode88 - 合并两个有序数组
06-22
02
LeetCode1 - 两数之和
06-22
03
LeetCode1603 - 设计停车系统
06-21
更多文章>
Theme by Vdoing | Copyright © 2021-2022 zfprotectors | 闽ICP备2021014222号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式