Golang学习:基础知识篇(二)—— 数组及切片

Golang学习:基础知识篇(二)—— 数组及切片

  • 前言
  • 什么是Golang?
  • Go语言的基础语法
  • 数组
    • 声明数组
    • 初始化数组
    • 访问数组
    • 知识点补充
  • 切片
    • 定义切片
    • 切片初始化
    • len() 和 cap() 函数
    • 空(nil)切片
    • 切片截取
    • append() 和 copy() 函数
    • 知识点补充

前言

很久之前就想学Go语言了,但是一直有其他东西要学,因为我学的是Java嘛,所以后面学的东西一直是跟Java相关的。

最近来到公司实习,需要用到Go语言,所以就趁着这个机会把Go学了。
在这里插入图片描述

什么是Golang?

简单来说就是由Google公司的Robert Griesemer,Rob Pike和Ken Thompson设计的一种静态类型、编译型语言。它在2009年正式对外公开,目标是解决大规模软件工程中的问题。Go语言的语法简洁清晰,易于学习和使用,编译速度快,具有垃圾回收功能,并且拥有强大的标准库。

Go语言的主要目标是将静态语言的安全性和高效性与动态语言的易开发性进行有机结合,达到完美平衡,从而使编程变得更加有乐趣,而不是在艰难抉择中痛苦前行。Go语言设计最本质的初衷就是简单,希望程序员的工作量最小化,利用Go本身少量的特性,并通过组合的方式去解决实际问题。

Go语言的基础语法

前一章马马虎虎地把数组之前的一些东西简单梳理了一遍,今天讲一些数组之后的知识。

推荐学习教程:菜鸟教程 | Go语言

我会更侧重讲一些网上教程没有,或者没讲清楚的一些东西。

数组

声明数组

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:

var arrayName [size]dataType

其中,arrayName 是数组的名称,size 是数组的大小,dataType 是数组中元素的数据类型。

以下定义了数组 balance 长度为 10 类型为 float32:

var balance [10]float32

初始化数组

以下演示了数组初始化:

以下实例声明一个名为 numbers 的整数数组,其大小为 5,在声明时,数组中的每个元素都会根据其数据类型进行默认初始化,对于整数类型,初始值为 0。

var numbers [5]int

还可以使用初始化列表来初始化数组的元素:

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

以上代码声明一个大小为 5 的整数数组,并将其中的元素分别初始化为 1、2、3、4 和 5。

另外,还可以使用 := 简短声明语法来声明和初始化数组:

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

以上代码创建一个名为 numbers 的整数数组,并将其大小设置为 5,并初始化元素的值。

注意:在 Go 语言中,数组的大小是类型的一部分,因此不同大小的数组是不兼容的,也就是说 [5]int 和 [10]int 是不同的类型。

如果数组长度不确定,可以使用 … 代替数组的长度,编译器会根据元素个数自行推断数组的长度:

var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
或
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

如果设置了数组的长度,我们还可以通过指定下标来初始化元素:

//  将索引为 13 的元素初始化
balance := [5]float32{1:2.0,3:7.0}

访问数组

其实和Java一样,注意一下Go语言的语法格式就行。然后就是Go中也有一些操作数组的函数,例如

len(arr):返回数组 arr 的长度。range:常与 for 循环一起使用,用于遍历数组。它返回两个值:索引和该索引处的值

其实,Go 语言中的切片(slices)提供了更多的内置函数,如 append 和 copy。切片是对数组的抽象,使用得更为广泛。

知识点补充

这里简单对range遍历数组2进行一个说明,后续实验要是碰到了再做记录

在 Go 语言中,range 关键字用于 for 循环中迭代数组、切片、通道或集合的元素。在数组和切片中,它返回元素的索引和索引对应的值。

以下是一个使用 range 遍历数组的例子:

nums := []int{2, 3, 4}
for i, num := range nums {fmt.Printf("index: %d, value: %d\n", i, num)
}

在这个例子中,i 是索引,num 是索引 i 对应的值。这段代码会打印出数组 nums 的每个元素及其索引。

你也可以只获取索引或值。如果只想获取索引,可以这样写:

for i := range nums {fmt.Printf("index: %d\n", i)
}

如果只想获取值,可以这样写:

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

在这两个例子中,我们使用了空白标识符 _ 来忽略 range 返回的某个值。

注意事项:

  • range 在每次迭代时都会返回两个值(索引和值),即使你只需要其中一个。如果你不需要其中一个值,你可以使用空白标识符 _ 来忽略它。
  • 在 Go 语言中,数组的大小是类型的一部分,因此不同大小的数组是不兼容的²。
  • 当使用 range 遍历数组或切片时,返回的值是元素的副本,而不是元素本身。这意味着如果你在循环体内修改了元素,原数组并不会被改变。

切片

切片是Go语言中一个新的概念:Go 语言切片是对数组的抽象。

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用。

于是Go 提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

定义切片

你可以声明一个未指定大小的数组来定义切片:

var identifier []type

切片不需要说明长度。

或使用 make() 函数来创建切片:

var slice1 []type = make([]type, len)也可以简写为slice1 := make([]type, len)

也可以指定容量,其中 capacity 为可选参数。

make([]T, length, capacity)

这里 len 是数组的长度并且也是切片的初始长度。

切片初始化

直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3 (这两玩意是啥后面会讲)。

s :=[] int {1,2,3 } 

初始化切片 s,是数组 arr 的引用。

s := arr[:] 

将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片。

s := arr[startIndex:endIndex] 

默认 endIndex 时将表示一直到arr的最后一个元素。

s := arr[startIndex:] 

默认 startIndex 时将表示从 arr 的第一个元素开始。

s := arr[:endIndex] 

通过切片 s 初始化切片 s1。

s1 := s[startIndex:endIndex] 

通过内置函数 make() 初始化切片s,[]int 标识为其元素类型为 int 的切片。

s :=make([]int,len,cap) 

len() 和 cap() 函数

切片是可索引的,并且可以由 len() 方法获取长度。

切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。

这里讲一下长度和容量,这是是两个不同的概念。

  • 长度:切片的长度是指它所包含的元素个数。可以通过len(s)函数来获取切片的长度。

  • 容量:切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。可以通过cap(s)函数来获取切片的容量。

容量必须大于或等于长度,因为长度表示切片当前的元素数量,而容量表示切片可以访问的元素数量。换句话说,容量表示了切片底层数组的大小,而长度则表示了当前正在使用的元素的数量。

当你向切片添加元素时,如果切片的容量不足以容纳更多的元素,Go语言会自动为切片分配一个新的底层数组,并将原有的元素复制到新数组中。这就是为什么我们说切片是动态的:它们可以根据需要增长和缩小。

所以说容量这个引入还是很有必要的,以下是一些关于容量的重要点:

  • 性能优化:当你知道你的切片可能会增长到多大时,你可以在创建切片时就设置一个足够大的容量。这样,当你向切片添加元素时,Go语言就不需要频繁地分配新的底层数组和复制元素,从而提高性能。
  • 避免不必要的内存分配:如果你没有预先设定一个足够大的容量,那么每次向切片添加元素时,如果容量不足,Go语言都会为切片分配一个新的底层数组。这可能会导致大量的内存分配和释放,从而降低程序的性能。
  • 控制切片的增长:通过管理切片的容量,你可以更好地控制切片的增长。例如,你可以通过限制切片的容量来防止它无限制地增长。

考一下,下面这种写法是否正确?

s :=make([]int,4,8)
s[6]:=3 

这样写是不正确的。在Go语言中,当你创建一个切片时,例如s := make([]int, 4, 8),这个切片的长度是4,容量是812。

虽然容量是8,但是你只能访问长度内的元素,也就是索引0到3的元素。

所以,当你试图访问或修改索引为6的元素,比如s[6] = 3,将会得到一个运行时错误:index out of range……。

如果你想要扩展切片的长度,你可以使用append函数实现增加元素。

空(nil)切片

一个切片在未初始化之前默认为 nil,长度为 0。示例如下:

package mainimport "fmt"func main() {var numbers []intprintSlice(numbers)if(numbers == nil){fmt.Printf("切片是空的")}
}func printSlice(x []int){fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

以上实例运行输出结果为:

len=0 cap=0 slice=[]
切片是空的

切片截取

可以通过设置下限及上限来设置截取切片 [lower-bound:upper-bound],可以省略前面或者后面,或者干脆都省了。(前面应该有出现过具体说明,就不细讲了)

append() 和 copy() 函数

如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。

下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法。

知识点补充

问:改变切片的值会影响到原来数组的值吗?切片可以大于原数组吗

在Go语言中,切片是对数组的引用。因此,如果改变了切片中的元素,那么原数组中对应的元素也会被改变。这是因为切片的内部包含一个指向底层数组的指针,所以函数对切片的修改也会反应到底层数组上。

且切片可以大于原数组。当向切片添加元素时,如果切片的容量不足以容纳更多的元素,Go语言会自动为切片分配一个新的底层数组,并将原有的元素复制到新数组中。

这就意味着,尽管切片开始时是基于原数组创建的,但在扩容过程中,它可能会脱离原数组,使用一个全新的底层数组。(是不是很神奇 @_@😉)

问:那么当切片大于原数组,并分配了一个新的底层数组后,对切片进行修改还会影响到原来的数组吗?

当切片扩容并分配了一个新的底层数组后,对切片进行修改不会影响到原来的数组。这是因为在扩容过程中,Go语言会为切片分配一个新的底层数组,并将原有的元素复制到新数组中。

此时,切片已经不再引用原数组,而是引用新的底层数组。因此,对切片的修改不会影响到原数组。

问:切片和数组的使用场景有哪些,什么时候我们会需要用到切片?

切片和数组在Go语言中都是重要的数据结构,但它们有一些关键的区别:

  1. 长度:数组的长度是固定的,而切片的长度是可变的。数组在定义时就需要指定长度和元素类型,例如:[4]int表示一个包含四个整数的数组,数组的大小是固定的。切片则可以在定义时长度可以为空,也可以指定一个初始长度。

  2. 值类型与引用类型:数组是值类型,而切片是引用类型。这意味着当数组被赋值给另一个变量时,会创建一个新的数组副本,而切片则是共享底层数组的¹²³⁴。

  3. 内存分配:数组的内存空间是在定义时分配的,其大小是固定的;切片的内存空间是在运行时动态分配的,其大小是可变的。

关于使用场景,数组和切片各有其优势:

  • 数组:由于数组长度固定,所以在知道确切元素数量且不需要动态改变时,使用数组是个不错的选择。例如,在实现一个俄罗斯方块游戏时,随机生成的积木其实就是一个二维数组。

  • 切片:相比之下,切片更加灵活且常用。它支持自动扩容,并且可以快速地操作一块数据集合。当你需要处理一个元素数量未知或需要动态改变的数据集合时,使用切片会更加方便。

问:切片的扩容机制是怎么样的?

在Go语言中,切片的扩容机制是这样的:

  1. 新扩容容量大于当前容量的2倍:如果新的扩容容量大于当前容量的2倍,那么新的容量就会被设置为新的扩容容量。

  2. 旧容量小于256:如果旧的容量小于256,那么新的容量会变为旧的容量的2倍。

  3. 旧容量大于等于256:如果旧的容量大于等于256,那么新的容量会不断地增加,每次增加的速率是1.25倍,直到新的容量大于或等于目标容量。

  4. 初始容量为0:如果初始的容量为0,那么新的容量就会被直接设置为目标容量。

然而,这只是理论上的计算。在实际操作中,Go语言还会进行一些优化操作,比如内存对齐等。因此,实际的扩容结果可能会比理论计算结果稍微大一些。


那么以上就是本次的内容了,在学习的过程中,可以多去敲敲代码,熟悉一下。也可以去菜鸟教程上面多看看,对新人挺友好的,也是我的公司同事推荐的教程网站。

后续也会不定期更新学习记录和一些学习实验。🤠

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

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

相关文章

ubuntu20.04安装FTP服务

安装 sudo apt-get install vsftpd# 设置开机启动并启动ftp服务 systemctl enable vsftpd systemctl start vsftpd#查看其运行状态 systemctl status vsftpd #重启服务 systemctl restart vsftpdftp用户 sudo useradd -d /home/ftp/ftptest -m ftptest sudo passwd ftptest…

使用 Python 和蒙特卡罗计算未来股价走势以及历史波动率和隐含波动率

一、简介 预测金融市场是定量精度和全球经济细微差别的复杂融合。在这一探索中,蒙特卡罗模拟脱颖而出,成为首要的统计工具,指导我们对未来股票价格的理解。 这种方法以摩纳哥著名的蒙特卡洛赌场命名,并不依靠运气,而是植根于严格的概率模型。想象一下在受控环境中精心策划…

vue3后台管理框架之技术栈

vue3全家桶技术 基础构建: vue3vite4TypeScript 代码格式 : eslintprettystylelint git生命周期钩子: husky css预处理器: sass ui库: element-plus 模拟数据: mock 网络请求: axios 路由: vue…

SAP MM学习笔记37 - 请求书照合中的 追加请求/追加Credit 等概念/ 请求书的取消

有关请求书照合,之前学习了一部分,现在再来学其中的一些概念。 其实这些概念也许并不常用,但是你又不能不知道,因为客户会问。 有关请求书,贴一些以前学习的文章,以方便阅读。 SAP MM学习笔记33 - 请求书…

38.迪杰斯特拉(Dijkstra)算法

概述 我们在上一篇中面对修路的问题讲述了普利姆算法的实现方式,本篇我们参照迪杰斯特拉算法来对修路问题做进一步拆解。 我们回顾一下之前的问题: “要想富,先修路”,郝乡长最近为了德胜乡修路的事情愁白了头。 得胜乡有A、B、C…

《3D 数学基础》几何检测-最近点

目录 1. 直线上的最近点 2. 射线上的最近点 3. 点到平面的距离 4. 圆或球上的最近点 5. AABB上的最近点 1. 直线上的最近点 q是距离q的最近点,也就是q在直线上的投影。 其中p是直线上的点(向量表示),n是直线的法向量&#x…

selenium教程 —— css定位

说明:本篇博客基于selenium 4.1.0 selenium-css定位 element_css driver.find_element(By.CSS_SELECTOR, css表达式) 复制代码 css定位说明 selenium中的css定位,实际是通过css选择器来定位到具体元素,css选择器来自于css语法 css定位优点…

史上最短的“牛熊转换”:BTC价格昨夜起飞,但却来自一条假新闻!

昨夜,加密市场经历了史上最短的一次“牛熊转换”。 在短短10分钟内,BTC快速走出多根阳线,价格直接起飞,连续突破28000美元、29000美元、30000美元的整数关口,最高触及30535.8美元,涨幅近10%(数据…

接口自动化测试之HttpRunner测试框架

引言 接口自动化测试的实现方案有很多,没有编程基础的可以使用 PostmanNewman 或 JmeterAnt 来实现,有编程基础的则可以结合自动化测试框架来实现。基于Python的测试框架有:Unittest、HttpRunner、Robot Framework、Pytest等,本文…

python接口自动化测试(六)-unittest-单个用例管理

前面五节主要介绍了环境搭建和requests库的使用,可以使用这些进行接口请求的发送。但是如何管理接口案例?返回结果如何自动校验?这些内容光靠上面五节是不行的,因此从本节开始我们引入python单元测试框架 unittest,用它…

OpenCV模板匹配实现银行卡数字识别

目录 1,项目流程 2,代码流程解读 2.1 导入工具包 2.2 设置参数 2.3 指定信用卡类型 2.4 展示图像 ​编辑 2.5 读取一个模板图像 2.6 转化为灰度图--------->再转化为二值图像 2.7 计算轮廓 ​编辑 2.8 导入我们要识别的图像&…

【力扣每日一题】2023.10.13 避免洪水泛滥

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 给我们一个一维数组,元素为0表示对应日期不下雨,非0则表示对应日期对应号的湖泊下雨,下雨之后会导致该…

Spacedrive:开源跨平台文件管理 | 开源日报 No.57

denoland/deno Stars: 91.2k License: MIT Deno 是一个简单、现代和安全的 JavaScript 和 TypeScript 运行时,使用 V8 引擎并用 Rust 构建。其主要功能包括: 默认情况下具有高度安全性,除非显式启用,否则无法访问文件、网络或环…

哪种烧录单片机的方法合适?

哪种烧录单片机的方法合适? 首先,让我们来探讨一下单片机烧录的方式。虽然单片机烧录程序的具体方法会因为单片机型号、然后很多小伙伴私我想要嵌入式资料,通宵总结整理后,我十年的经验和入门到高级的学习资料,只需一…

Android versionCode会变成指定数值加001、002、003等后缀

“活久见”—今天遇到个奇怪的问题,指定的versionCode最终在打包出来的apk中,versionCode变成(指定数值 00X的形式) 如下所示: 注:当前build.gradle中的versionCode为26 后来搜索代码,发现原来是这个配置导…

Vue检测数据的原理

Vue能够对用户的数据进行响应式,也就是你在data中写了什么,你在模板中用到data的部分就会渲染成什么,那么Vue是怎么知道用户修改了data中的数据变化并对模板重新进行解析的呢? 在Vue将数据存储为自身的_data之前,Vue会…

Unity Ugui 顶点颜色赋值

一、效果图 如下图:图片和文字的颜色都可以渐变,透明度也可以渐变。 原理分析: 不管是图片Image或是文本Text,它们都是网络Mesh来渲染网格是由很多三角形组成,那么我们根据坐标修改三角形的颜色即可实现。 工程源码…

安达发|AI人工智能APS系统:工业4.0的智能引擎

在工业4.0的背景下,人工智能(AI)和APS智能排程软件已经成为智能工厂的标准配置。它们通过集成先进的信息技术、通信技术和物联网技术,实现了生产过程的智能化、自动化和数据化,从而提高了生产效率、降低了生产成本、提…

DIN模型和SIM模型原理与实践

文章目录 1.DIN模型原理缺点 2.SIM模型原理算法步骤1.查找2.注意力机制 参考文献 1.DIN模型 原理 计算用户Last N向量的加权平均权重是候选物品与Last N物品的相似度 缺点 注意力层的计算量正比于n(用户行为序列的长度)只能记录最近的几百个物品&…

Elasticsearch:什么是大语言模型 (LLMs)?

假设你想参加流行的游戏节目 Jeopardy(这是一个美国电视游戏节目,参赛者将获得答案并必须猜测问题)。 要参加演出,你需要了解任何事情的一切。 所以你决定在接下来的三年里每天都花时间阅读互联网上的所有内容。 你很快就会意识到…