首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01|前世今生:你不得不了解的Go的历史和现状
02|拒绝“Hello and Bye”:Go语言的设计哲学是怎么一回事?
03|配好环境:选择一种最适合你的Go安装方法
04|初窥门径:一个Go程序的结构是怎样的?
05|标准先行:Go项目的布局标准是什么?
06|构建模式:Go是怎么解决包依赖管理问题的?
07|构建模式:Go Module的6类常规操作
08|入口函数与包初始化:搞清Go程序的执行次序
09|即学即练:构建一个Web服务就是这么简单
10|变量声明:静态语言有别于动态语言的重要特征
11|代码块与作用域:如何保证变量不会被遮蔽?
12|基本数据类型:Go原生支持的数值类型有哪些?
13|基本数据类型:为什么Go要原生支持字符串类型?
14|常量:Go在“常量”设计上的创新有哪些?
15|同构复合类型:从定长数组到变长切片
16|复合数据类型:原生map类型的实现机制是怎样的?
17|复合数据类型:用结构体建立对真实世界的抽象
18|控制结构:if的“快乐路径”原则
19|控制结构:Go的for循环,仅此一种
20|控制结构:Go中的switch语句有哪些变化?
21|函数:请叫我“一等公民”
22|函数:怎么结合多返回值进行错误处理?
23|函数:怎么让函数更简洁健壮?
24|方法:理解“方法”的本质
25|方法:方法集合与如何选择receiver类型?
26|方法:如何用类型嵌入模拟实现“继承”?
27|即学即练:跟踪函数调用链,理解代码更直观
28|接口:接口即契约
29|接口:为什么nil接口不等于nil?
30|接口:Go中最强大的魔法
31|并发:Go的并发方案实现方案是怎样的?
32|并发:聊聊Goroutine调度器的原理
33|并发:小channel中蕴含大智慧
34|并发:如何使用共享变量?
35|即学即练:如何实现一个轻量级线程池?
36|打稳根基:怎么实现一个TCP服务器?(上)
37|代码操练:怎么实现一个TCP服务器?(中)
38|成果优化:怎么实现一个TCP服务器?(下)
39 | 驯服泛型:了解类型参数
40|驯服泛型:定义泛型约束
41 | 驯服泛型:明确使用时机
当前位置:
首页>>
技术小册>>
Go语言入门实战经典
小册名称:Go语言入门实战经典
### 第15章 同构复合类型:从定长数组到变长切片 在Go语言的广阔天地中,复合类型占据了举足轻重的地位,它们为数据结构的构建提供了强大的支持。本章将深入探讨Go语言中的两种紧密相关但各具特色的同构复合类型——定长数组(Array)与变长切片(Slice),解析它们的定义、特性、使用场景以及相互之间的转换,帮助读者从理论到实践全面掌握这两种类型。 #### 15.1 引言 在编程的世界里,数据结构的合理设计是高效编程的基石。Go语言通过提供丰富的内置类型以及灵活的复合类型,极大地简化了复杂数据结构的实现。其中,数组和切片作为处理序列数据的两种基本手段,不仅各自拥有独特的优势,而且在很多场景下能够相互协作,共同构建出高效、灵活的数据处理方案。 #### 15.2 定长数组(Array) ##### 15.2.1 定义与声明 数组是Go语言中一种基础的数据结构,用于存储固定数量的同一类型元素。数组的长度是其类型的一部分,在声明时必须指定。数组的声明语法如下: ```go var arr [N]ElementType ``` 其中,`N` 是数组的长度,`ElementType` 是数组中元素的类型。例如,声明一个存储5个整数的数组: ```go var intArray [5]int ``` 也可以在声明时直接初始化数组: ```go var intArray = [5]int{1, 2, 3, 4, 5} // 或者更简洁的 intArray := [5]int{1, 2, 3, 4, 5} ``` ##### 15.2.2 特性 - **固定长度**:数组一旦创建,其长度便不可改变。 - **值类型**:数组是值类型,当数组作为函数参数传递时,会进行值拷贝。 - **内存连续**:数组在内存中占用连续的空间,这使得对数组元素的访问非常高效。 ##### 15.2.3 使用场景 尽管数组的长度固定限制了其灵活性,但在一些场景下,如已知固定大小的数据集合(如月份名称、星期几等),使用数组可以提高效率和直观性。 #### 15.3 变长切片(Slice) ##### 15.3.1 定义与声明 切片是对数组的抽象,它提供了对数组的动态访问能力,能够动态地增长和缩小。切片不是数组的拷贝,而是对数组的引用,其内部包含指向数组元素的指针、切片长度以及切片容量。切片的声明和初始化相对灵活: ```go var slice []ElementType slice := []ElementType{} // 或者直接初始化 slice := []int{1, 2, 3} ``` ##### 15.3.2 特性 - **动态长度**:切片的长度可以动态变化,支持append操作来增加元素。 - **引用类型**:切片是引用类型,当切片作为函数参数传递时,传递的是其底层数组的引用(而非拷贝)。 - **内存灵活**:切片通过内部指针和长度、容量字段实现了对底层数组的灵活访问,提高了内存使用的效率。 ##### 15.3.3 切片操作 切片支持多种操作,包括但不限于: - **切片截取**:通过`slice[start:end]`语法截取原切片的一部分,生成新的切片。 - **append操作**:通过`append(slice, elements...)`向切片追加元素,可能引发底层数组的扩容。 - **copy函数**:使用`copy(dst, src []T) int`函数将源切片`src`的元素复制到目标切片`dst`中,返回复制的元素数量。 ##### 15.3.4 使用场景 切片是Go语言中处理序列数据的首选方式,其灵活性和高效性使得它在处理未知大小的数据集合时尤为强大。无论是函数间的数据传递、集合的遍历修改,还是并发编程中的数据共享,切片都展现出了其独特的优势。 #### 15.4 数组与切片的转换 虽然数组和切片在定义和使用上有所不同,但它们之间可以相互转换,这种转换是Go语言灵活性的体现之一。 - **数组转切片**:由于切片是对数组的引用,因此任何数组都可以被直接转换为切片,而无需进行额外的拷贝操作。转换方式简单直接: ```go array := [5]int{1, 2, 3, 4, 5} slice := array[:] // 将整个数组转换为切片 ``` - **切片转数组**:切片不能直接转换为数组,因为切片是动态长度的,而数组的长度是固定的。但可以通过遍历切片元素,手动将其赋值给一个指定长度的数组来实现间接转换,但这通常不是推荐的做法,因为它涉及额外的拷贝和可能的类型不匹配风险。 #### 15.5 实战案例 为了更好地理解数组和切片的应用,我们通过一个简单的实战案例来演示它们的使用。 假设我们需要实现一个功能,该功能能够接收用户输入的多个整数,计算并返回这些整数的平均值。考虑到用户可能输入任意数量的整数,使用切片来存储这些整数显然是更合适的选择。 ```go package main import ( "fmt" ) func main() { // 假设这是用户输入的整数序列,这里用切片模拟 nums := []int{1, 2, 3, 4, 5} // 计算平均值 avg := calculateAverage(nums) // 输出结果 fmt.Printf("The average is: %.2f\n", avg) } // calculateAverage 计算切片中整数的平均值 func calculateAverage(nums []int) float64 { sum := 0 for _, num := range nums { sum += num } return float64(sum) / float64(len(nums)) } ``` 在这个案例中,我们使用了切片来存储用户输入的整数序列,并利用切片提供的遍历和长度获取功能来计算平均值。这展示了切片在处理动态数据时的便利性和高效性。 #### 15.6 小结 本章深入探讨了Go语言中的定长数组和变长切片这两种同构复合类型。我们了解了数组的定义、特性及使用场景,掌握了切片的声明、特性、操作方法及使用场景,并学习了数组与切片之间的转换方法。通过实战案例的演示,我们进一步加深了对这两种类型及其应用的理解。掌握数组和切片的使用,是成为Go语言高手的必经之路。
上一篇:
14|常量:Go在“常量”设计上的创新有哪些?
下一篇:
16|复合数据类型:原生map类型的实现机制是怎样的?
该分类下的相关小册推荐:
WebRTC音视频开发实战
go编程权威指南(四)
深入浅出Go语言核心编程(八)
企业级Go应用开发从零开始
Go 组件设计与实现
深入浅出Go语言核心编程(七)
Go语言从入门到实战
深入浅出Go语言核心编程(六)
Go开发权威指南(上)
go编程权威指南(三)
深入浅出Go语言核心编程(四)
深入浅出Go语言核心编程(三)