第 8 章 - Go语言 数组与切片

在Go语言中,数组和切片是两种非常基础且重要的数据结构。它们都用来存储一系列相同类型的元素,但是它们之间存在一些关键的区别。下面我们将详细探讨数组和切片的定义、使用以及切片的动态特性。

数组的定义和使用

定义

在Go语言中,数组是一个固定长度的序列,一旦定义了数组的大小,就不能改变。数组的定义方式如下:

var arr [n]T

这里 n 是数组的长度,T 表示数组元素的类型。例如,定义一个包含5个整数的数组:

var numbers [5]int
初始化

数组可以使用值列表来初始化:

numbers := [5]int{1, 2, 3, 4, 5}

如果提供的值少于数组的长度,其余的元素将被默认初始化为该类型的零值(对于整型来说是0):

numbers := [5]int{1, 2} // 相当于 [1, 2, 0, 0, 0]
访问元素

可以通过索引来访问数组中的元素。索引从0开始:

firstElement := numbers[0] // 获取第一个元素
lastElement := numbers[4]  // 获取最后一个元素
遍历

可以使用for循环来遍历数组的所有元素:

for i := 0; i < len(numbers); i++ {fmt.Println(numbers[i])
}

或者使用range关键字来简化遍历:

for index, value := range numbers {fmt.Printf("Index: %d Value: %d\n", index, value)
}

切片的定义和操作

定义

切片是对数组的一个抽象,它没有固定的长度,可以动态地增长或缩小。定义一个切片的方式如下:

var slice []T

这里 T 是切片元素的类型。切片可以基于数组创建,也可以直接声明并初始化:

slice := []int{1, 2, 3, 4, 5}
操作
  • 添加元素:使用append函数可以向切片添加元素。

    slice = append(slice, 6) // 添加一个元素
    
  • 切片操作:通过指定开始和结束索引来创建新的切片。

    newSlice := slice[1:3] // 创建一个新的切片,包含原切片的第二个到第三个元素
    
  • 容量:切片有一个长度(当前元素的数量)和一个容量(可以容纳的最大元素数量,不需重新分配内存)。

    length := len(slice)
    capacity := cap(slice)
    

切片的动态特性

切片的一个重要特性就是它的动态性,这使得它可以方便地扩展和收缩。当你向一个已满的切片添加新元素时,append函数会自动分配更大的底层数组,并复制旧数组的数据到新数组中,然后返回更新后的切片。这个过程对调用者是透明的,但需要注意的是,频繁的扩容操作可能会导致性能开销。

此外,由于切片共享相同的底层数组,修改一个切片中的元素可能会影响到其他引用同一数组的切片。因此,在处理多个切片时需要特别小心,确保不会因为意外的副作用而引入错误。

以上就是Go语言中数组与切片的基本概念和使用方法。希望这些信息对你有所帮助!

当然可以,接下来我们继续深入探讨Go语言中切片的一些高级特性和最佳实践,包括如何高效地使用切片、常见的陷阱以及一些优化技巧。

切片的高级特性

多维切片

Go语言支持多维切片,可以用来表示矩阵或其他多维数据结构。例如,创建一个3x3的二维切片:

matrix := [][]int{{1, 2, 3},{4, 5, 6},{7, 8, 9},
}

访问二维切片中的元素:

value := matrix[1][2] // 获取第二行第三列的值,即6
切片的复制

使用copy函数可以将一个切片的内容复制到另一个切片中。copy函数会复制两个切片中较短的那个切片的长度。

src := []int{1, 2, 3, 4, 5}
dst := make([]int, 3)
copy(dst, src) // dst 将变为 [1, 2, 3]
切片的排序

可以使用sort包来对切片进行排序。例如,对整数切片进行升序排序:

import "sort"numbers := []int{5, 3, 4, 1, 2}
sort.Ints(numbers) // numbers 将变为 [1, 2, 3, 4, 5]
自定义排序

如果需要对复杂类型进行排序,可以实现sort.Interface接口:

type Person struct {Name stringAge  int
}type ByAge []Personfunc (a ByAge) Len() int           { return len(a) }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }people := []Person{{"Alice", 30},{"Bob", 25},{"Charlie", 35},
}sort.Sort(ByAge(people)) // 按年龄升序排序

常见陷阱

共享底层数组

切片共享同一个底层数组,因此修改一个切片可能会影响其他切片。例如:

a := []int{1, 2, 3, 4, 5}
b := a[1:3] // b 是 a 的子切片
b[0] = 10   // 修改 b 也会影响 a
fmt.Println(a) // 输出 [1 10 3 4 5]
切片的零值

切片的零值是nil,而不是一个空切片。在使用切片之前,需要检查其是否为nil

var s []int
if s == nil {fmt.Println("s is nil")
}

性能优化

预分配容量

在知道切片最终大小的情况下,预分配容量可以减少内存分配次数,提高性能:

s := make([]int, 0, 100) // 预分配 100 个元素的容量
for i := 0; i < 100; i++ {s = append(s, i)
}
使用make函数

使用make函数可以更高效地创建切片,因为它允许指定初始容量:

s := make([]int, 5, 10) // 创建一个长度为 5,容量为 10 的切片

最佳实践

避免不必要的切片拷贝

在传递大切片时,尽量避免不必要的拷贝,可以传递切片的引用:

func processSlice(s []int) {// 处理切片
}
使用...参数

在函数中接受可变数量的参数时,可以使用...参数:

func sum(nums ...int) int {total := 0for _, num := range nums {total += num}return total
}

总结

切片是Go语言中非常强大和灵活的数据结构,掌握其基本操作和高级特性对于编写高效、可靠的代码至关重要。希望上述内容能够帮助你更好地理解和使用Go语言中的切片。

接下来我们将继续探讨Go语言中切片的一些更高级的特性和使用场景,包括切片的并发安全、切片的内存管理、常见错误及其解决方法等。

并发安全

切片的并发访问

切片不是线程安全的。在多 goroutine 中同时读写同一个切片会导致数据竞争(data race)。为了确保并发安全,可以使用互斥锁(sync.Mutex)或读写锁(sync.RWMutex)来保护切片的访问。

示例:使用互斥锁
package mainimport ("fmt""sync"
)func main() {var mu sync.Mutexvar slice []intvar wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func(i int) {defer wg.Done()mu.Lock()slice = append(slice, i)mu.Unlock()}(i)}wg.Wait()fmt.Println(slice)
}
示例:使用读写锁
package mainimport ("fmt""sync"
)func main() {var rwMu sync.RWMutexvar slice []intvar wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func(i int) {defer wg.Done()rwMu.Lock()slice = append(slice, i)rwMu.Unlock()}(i)}wg.Wait()fmt.Println(slice)
}

内存管理

切片的内存分配

切片的内存分配是自动管理的,但了解其内部机制有助于优化性能。切片底层是一个指向数组的指针,包含长度和容量信息。当切片的容量不足以容纳新元素时,append函数会分配新的底层数组,并将旧数组的数据复制到新数组中。

避免内存泄漏

在使用大容量切片时,需要注意避免内存泄漏。如果不再需要某个切片,可以将其设置为nil,以便垃圾回收器能够回收其占用的内存。

示例:避免内存泄漏
package mainimport ("fmt"
)func main() {largeSlice := make([]int, 1000000)// 使用 largeSlice 进行一些操作// 不再需要 largeSlice 时,将其设置为 nillargeSlice = nilfmt.Println("largeSlice has been released")
}

常见错误及其解决方法

越界访问

切片的索引访问必须在有效范围内,否则会引发运行时错误。可以通过len函数检查切片的长度来避免越界访问。

示例:检查索引
package mainimport ("fmt"
)func main() {slice := []int{1, 2, 3}index := 3if index >= 0 && index < len(slice) {fmt.Println(slice[index])} else {fmt.Println("Index out of bounds")}
}
未初始化的切片

使用未初始化的切片(即nil切片)时,需要先检查其是否为nil,以避免运行时错误。

示例:检查 nil 切片
package mainimport ("fmt"
)func main() {var slice []intif slice != nil {fmt.Println(len(slice))} else {fmt.Println("Slice is nil")}
}

高效的切片操作

使用cap函数

cap函数返回切片的容量,可以利用这一点来优化内存分配。例如,如果知道切片的最终长度,可以在初始化时预分配足够的容量。

示例:预分配容量
package mainimport ("fmt"
)func main() {finalLength := 100slice := make([]int, 0, finalLength)for i := 0; i < finalLength; i++ {slice = append(slice, i)}fmt.Println(slice)
}
使用copy函数

copy函数可以高效地复制切片内容,尤其是在处理大数据量时。

示例:复制切片
package mainimport ("fmt"
)func main() {src := []int{1, 2, 3, 4, 5}dst := make([]int, 3)n := copy(dst, src)fmt.Println("Copied", n, "elements:", dst)
}

总结

切片是Go语言中非常强大和灵活的数据结构,但在使用时需要注意并发安全、内存管理和常见错误。通过合理使用锁、预分配容量和检查索引等技术,可以编写出高效、可靠的代码。希望上述内容能够帮助你更好地理解和使用Go语言中的切片。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/60238.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux开发讲课49--- Linux 启动过程分析

理解运转良好的系统对于处理不可避免的故障是最好的准备。 启动过程非常简单。内核在单核上以单线程和同步状态启动&#xff0c;似乎可以理解。但内核本身是如何启动的呢&#xff1f;initrd&#xff08;initial ramdisk&#xff09; 和引导程序(bootloader)具有哪些功能&#…

vscode中执行git合并操作需要输入合并commit信息,打开的nano小型文本编辑器说明-

1.前提: VScode中的git组件执行任何合并动作的时候需要提交远程合并的commit信息,然后编辑器自动打开的是nano文本编辑器 2.nano编辑器说明: 1.保存文件:按 Ctrl + O,然后按 Enter 来保存文件。 2.退出编辑器:按 Ctrl + X,这会退出 nano。 3.剪切文本:移动光标到要剪…

Java 并发相关集合

文章目录 一、CopyOnWriteArrayList 源码1.1. 概述1.2. 思想1.3. 源码① 数据结构② 初始化③ 添加元素④ 获取元素⑤ 删除元素 二、ArrayBlockingQueue 源码2.1. 概述2.2. 思想2.3. 源码① 数据结构② 初始化③ 阻塞式获取和新增元素④ 非阻塞式获取和新增元素⑤ 指定超时时间…

AutoDL使用简记

AutoDL使用简记 一、前言二、AutoDL显卡配置、价格简介2.1显卡配置及价格2.2计费方式的种类2.3开通会员及优惠 三、AutoDL使用教程3.1选择深度学习架构3.2文件传输3.3运行程序 一、前言 在进行深度学习模型训练时&#xff0c;通常会面临本地显卡显存或者运行速度的不足&#x…

基于STM32智能电流表

采用STM32F103C8T6微控制器为核心&#xff0c;设计了一款精密的电流表。该电流表通过精确采集采样电阻上的分压信号&#xff0c;并进行信号放大处理&#xff0c;随后利用ADC&#xff08;模数转换器&#xff09;高效地捕获放大后的电压信号&#xff0c;通过一系列算法运算&#…

【harbor】离线安装2.9.0-arm64架构服务制作和升级部署

harbor官网地址&#xff1a;Harbor 参考文档可以看这里&#xff1a;部署 harbor 2.10.1 arm64 - 简书。 前提环境准备&#xff1a; 安装docker 和 docker-compose 先拉arm64架构的harbor相关镜像 docker pull --platformlinux/arm64 ghcr.io/octohelm/harbor/harbor-regist…

支持 Win10 的网络环境模拟(丢包,延迟,带宽)

升级 Windows 10 以后&#xff0c;原来各种网络模拟软件都挂掉了&#xff0c;目前能用的就是只有 clumsy&#xff1a; 唯一问题是不支持模拟带宽&#xff0c;那么平时要模拟一些糟糕的网络情况的话&#xff0c;是不太方便的&#xff0c;而开虚拟机用 Linux tc 或者设置个远程 l…

网页web无插件播放器EasyPlayer.js点播播放器遇到视频地址播放不了的现象及措施

在数字媒体时代&#xff0c;视频点播已成为用户获取信息和娱乐的重要方式。EasyPlayer.js作为一款流行的点播播放器&#xff0c;以其强大的功能和易用性受到广泛欢迎。然而&#xff0c;在使用过程中&#xff0c;用户可能会遇到视频地址无法播放的问题&#xff0c;这不仅影响用户…

.NET周刊【11月第2期 2024-11-10】

国内文章 .NET 全能高效的 CMS 内容管理系统 https://www.cnblogs.com/1312mn/p/18511224 SSCMS 是一个完全开源的企业级内容管理系统&#xff0c;基于 .NET Core 开发&#xff0c;适合跨平台部署。其特点包括支持多终端发布和功能插件&#xff0c;具有完善的权限控制和安全…

Pytorch从0复现worc2vec skipgram模型及fasttext训练维基百科语料词向量演示

目录 Skipgram架构 代码开源声明 Pytorch复现Skip-gram 导包及随机种子设置 维基百科数据读取 建立词频元组列表并根据词频排序 建立词频字典,word_id字典,id_word字典 二次采样 正采样与负采样 Skipgram模型类 模型训练 词向量输出 近义词寻找 fasttext训练Skip-…

如何详细查询全球药品研发的进度信息?

药品的研发进展对于医药研发人员来说&#xff0c;不仅是知识和技能的积累&#xff0c;更是职业精神和价值观的塑造。通过了解药品的研发进展&#xff0c;研发人员可以更好地提高自己的专业知识和技能&#xff0c;激发创新思维&#xff0c;保持专业竞争力&#xff0c;提高研发效…

从0学习React(11)

1. 引言 上个星期的工作内容是写IT资产管理的前端页面。其实&#xff0c;尽管我之前有一些前端开发的经验&#xff0c;但并不是很多。这次让我独立完成一个页面的开发&#xff0c;刚开始时我感到无从下手。 2. 初期的困惑和焦虑 我记得在星期一和星期二的时候&#xff0c;那…

第3章 需求 3.3需求的有效传递与度量

3.3 需求的有效传递与度量 收集需求是需要投入很多工作量的&#xff0c;同时需求必须有效传递到产品端才能最终发挥价值。而需求的有效传递却是一个容易被忽视的环节。 现实中存在各种需求传递方式&#xff0c;如口头传递、邮件传递、会议传递等&#xff0c;但这些需求都未被统…

Vue2中使用firefox的pdfjs进行文件文件流预览

文章目录 1.使用场景2. 使用方式1. npm 包下载,[点击查看](https://www.npmjs.com/package/pdfjs-dist)2. 官网下载1. 放到public文件夹下面2. 官网下载地址[点我,进入官网](https://github.com/mozilla/pdf.js/tags?afterv3.3.122) 3. 代码演示4. 图片预览5. 如果遇到跨域或者…

vue3+vite 前端打包不缓存配置

最近遇到前端部署后浏览器得清缓存才能出现最新页面效果得问题 所以…按以下方式配置完打包就没啥问题了&#xff0c;原理很简单就是加个时间戳 /* eslint-disable no-undef */ import {defineConfig, loadEnv} from vite import path from path import createVitePlugins from…

RS485/RS422保护电路

由于GJB 151B没有雷击和浪涌测试要求&#xff0c;故不需要防雷器件。TVS管使用SMB6.5CA&#xff0c;共模电感选择LCHWCM-453228-510YT01&#xff0c;详细设计电路如下图所示&#xff0c;此设计可同时满足GJB 151B和DO 160G的标准。注意SMB封装的TVS管是600W&#xff0c;SMA封装…

CKA认证 | Day1 k8s核心概念与集群搭建

第一章 Kubernetes 核心概念 1、主流的容器集群管理系统 容器编排系统&#xff1a; KubernetesSwarmMesos Marathon 2、Kubernetes介绍 Kubernetes是Google在2014年开源的一个容器集群管理系统&#xff0c;Kubernetes简称K8s。 Kubernetes用于容器化应用程序的部署&#x…

《大模型应用开发极简入门》笔记

推荐序 可略过不看。 初识GPT-4和ChatGPT LLM概述 NLP的目标是让计算机能够处理自然语言文本&#xff0c;涉及诸多任务&#xff1a; 文本分类&#xff1a;将输入文本归为预定义的类别。自动翻译&#xff1a;将文本从一种语言自动翻译成另一种语言&#xff0c;包括程序语言。…

在AutoDL上部署一个自定义的Python环境并在pycharm上使用

#AutoDL #GPU #租显卡 如何在AutoDL上部署一个自定义的Python环境 下面将会给出如何在AutoDL部署一个自定义的Python环境的详细步骤&#xff0c;希望可以帮助到同样对于显卡具有需求的同学。 注册账号 首先登陆AutoDL官网&#xff1a;https://www.gpuhub.com/register 链接…

高级AI记录笔记(二)

学习位置 B站位置&#xff1a;红豆丨泥 UE AI 教程原作者Youtube位置&#xff1a;https://youtu.be/-t3PbGRazKg?siRVoaBr4476k88gct素材自备 提前将动画素材准备好 枪的武器插槽位置调整好 动画蓝图基本没什么变化 准备武器 在AI的接口蓝图中添加两个函数一个是装备武…