Go语言实战-第四章 数组,切片和映射

本文详细介绍了Go语言中数组、切片和映射的数据结构,包括它们的声明、初始化、操作特性以及在函数间传递的优势,强调了内存管理和性能优化的重要性。
摘要由CSDN通过智能技术生成

前言

任何语言在处理实际问题的时候,都需要与数据源交互,go语言提供了三种数据结构管理数据:数组,切片和映射

数组

首先是数组,与其他语言类似,go的数组长度固定,可以存储内置类型和结构类型,数组的内存连续,因而cpu可以长久缓存它,这样在遍历时速度也更快,由于元素类型相同且移动距离一定,所以索引速度也就快,如下图
在这里插入图片描述

数组声明时长度在类型前

var array [5]int

长度是固定的,如果要扩容只能再创建一个新的,在把原数组复制过去,数组初始化后,默认初始值是类型的零值,若要赋值

array: [5]int{10,20,30,40,50}

也可以不给长度值,自动推断长度

array: [...]int{10,20,30,40,50}

可以指定部分初始值,其他为空

array: [5]int{1:0,2:0}

访问数组时,利用索引,从0开始

  • 指针数组
array : =[5] *int {0:new(int),1:new(int)}

初始化则为指向整型

*array[0] = 1

在这里插入图片描述指针数组赋值时不复制实际值,只复制引用地址
如图是两个赋值后的数组,指向同一组值
在这里插入图片描述

  • 数组的互相赋值,只有在长度和类型都相同时才可以
    在这里插入图片描述
  • 多维数组
    多维数组声明
var array [4][2]int

初始化

在这里插入图片描述
访问或为元素赋值需要提供多个维度

array[a][b] = c

也可也访问一个子维度的数组

var a[2] int = array[1]
  • 函数传参时数组的使用
    在函数中传参如果用数组传,开销会相当大,在函数被调用时,会在栈上分配对应数组大小内存,然后把值复制进来,可以使用指针来指向数组,传参时使用指针替代,这样就节省了大量栈内存
// 分配一个需要 8 MB 的数组
var array [1e6]int
// 将数组的地址传递给函数 foo
foo(&array)
// 函数 foo 接受一个指向 100 万个整型值的数组的指针
func foo(array *[1e6]int) {
...
} 

这样操作节约内存,而且性能更好,但是由于指针指向的是原值,如果改变这个值,就会造成其他指向这块值的指针也拿到了变化后的值,这时候,就需要使用到切片

切片

切片的核心概念是动态数组,可以通过内置函数append按需分配大小,同时它不同于其他语言中的链式结构,切片也是内存连续的,享有索引,迭代以及垃圾回收优化的好处

  • 内部实现
    切片内部还是数组,它有一个指针指向底层数组,同时还有一个长度和最大容量
    在这里插入图片描述
  • 创建和初始化
    可以使用make函数创建切片,参数为切片长度和容量,如果不指定容量,默认和长度相同,长度不可以大于容量
// 其长度和容量都是 5 个元素
slice := make([]string, 5)
// 其长度为 3 个元素,容量为 5 个元素
slice := make([]int, 3, 5)

也可以创建时就初始化

// 其长度和容量都是 5 个元素
slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}
//利用索引局部初始化
slice : = []string{99:""}
  • 数组与切片的不同:在[ ]运算符里指定了一个值,就是数组,空的就是切片
// 创建有 3 个元素的整型数组
array := [3]int{10, 20, 30}
// 创建长度和容量都是 3 的整型切片
slice := []int{10, 20, 30}
  • nil切片,空切片
    如果声明时不初始化,就会创建一个nil切片
    创建nil切片
var slice []int

创建空切片
使用make函数

slice := make([]int, 0)

使用切片字面变量声明切片

slice := []int{10,20,30,40,50}
// 创建一个新切片
// 其长度为 2 个元素,容量为 4 个元素
newSlice := slice[1:3]

在这里插入图片描述
新切片指向旧的第一个元素,对于它来说,访问不到旧切片的[1]元素之前的元素

-长度和容量的计算
对底层数组容量是 k 的切片 slice[i:j]来说
长度: j - i
容量: k - i
也就是说容量就是切片头后面的内容,长度就是这个切片自身长度,如果修改长度外的元素就会引起异常,除非append扩容
把容量扩到长度里
在这里插入图片描述如上图,newSlice扩容后长度加1
在这里插入图片描述

如上图,如果长度扩容后超过容量,会创建一个长度足够的新底层数组,将原有底层数组copy进来,之后再追加新值,这里的增长规则是1000长度内翻倍,超过1000就每次增加25%

  • 创建切片时还可以使用第三个参数,索引,它可以控制新切片的容量 ,但是设置索引不能超出容量,否则会报错
  • 容量和长度一样的好处有,可以保证append即设立新底层数组,这样就不会与原数组发生内容重叠或者更改原数组内容
    如下两图是容量长度不一致和一致下的情况,(切片就相当于从头尾元素左侧边缘切了一下,这样比较形象)
    在这里插入图片描述
    在这里插入图片描述
  • 切片追加到切片
    切片追加就是相当于合并,比如3,4追加到1,2 就会变成1,2,3,4
  • 迭代切片
    go中提供range关键字配合for进行迭代
slice :=[]int{1,2,3,4,5}
for index,value := range slice {
	fmt.Printf("Index: %d Value: %d\n", index, value)
}

也可以用下划线替代索引

for _, value := range slice {
	fmt.Printf("Value: %d\n", value)
}

也有传统for循环方式

for index := 2; index < len(slice); index++ {
	fmt.Printf("Index: %d Value: %d\n", index, slice[index])
}

明显前两种比较简单

多维切片

切片和数组一样也有多维版本

slice:=[][]{{10},{100200}}

多维切片append

slice[0] = append(slice[0], 20)

在这里插入图片描述

函数间传递切片

切片尺寸很小,在函数间传递成本低,在 64 位架构的机器上,一个切片需要 24 字节的内存:指针字段需要 8 字节,长度和容量字段分别需要 8 字节,切片传递时传递的是切片自身,不涉及底层数组
在这里插入图片描述

映射内部实现,基本功能

在这里插入图片描述映射内部是键值对,可以基于键检索数据,同时内部是无序的,迭代时无法预测返回元素顺序,内部利用了散列表实现
在这里插入图片描述
这种散列就是把键值对放在这些桶里,在查找时可以减少定位次数,对于1000个元素,8次左右就可以定位到,而不需要最差查找1000次
映射内部主要有两个数据结构,第一个是一个数组,存储选择桶用的高八位,第二个是一个字节数组,存储所有的键后,又存了所有的值在这里插入图片描述
总结就是:映射是一个存储键值对的无序集合

创建初始化
//使用make函数创建,键类型string,值类型int
dict :=make(map(string)int)
//创建同时初始化,键值同为string
dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}

如下,切片也可以分别作为键或者值

dict := map[[]string]int{}
dict := map[int][]string{}

如果未初始化,则是一个nil映射,nil映射不能赋值,否则会报error
如下可以判断键是否存在,同时返回值

value, exists := colors["Blue"]
if exists {
fmt.Println(value)
}

或者判断值是否存在,返回键

value := colors["Blue"]
// 这个键存在吗?
if value != "" {
fmt.Println(value)
}
  • 如果要迭代映射,可以使用range
colors := map[string]string{
	"A":"1",
	"B":"2"
}

for key,value :=range colors{
	fmt.Printf("Key: $s Value: %s\n",key,value)
}
  • 如果要删除映射元素,可以用delete
delete(colors,"A")
函数间传递映射

在函数间传递映射不会制造副本,任何操作都会影响到映射的内容,并且对映射的引用也会随之变动
这一点类似于切片,保证了低成本的复制

后记

这一章内容很多,之后会补充上来,之前两章内容似乎也有些问题,之后会修改重新发布

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值