深入探讨Go语言中的切片与数组操作
在编程世界中,数组一直是非常流行的数据结构,主要有两个原因:其一是简单易懂,其二是非常灵活,可以存储多种不同类型的数据。在Go语言中,数组的用法有其独特的特点,但与此同时,Go语言的切片(Slices)功能更为强大,能够在大多数情况下替代数组的使用。接下来,本文将深入探讨Go语言中的数组与切片的使用方法及其优缺点。
基础数组操作
数组在Go中是固定长度的结构,长度定义在数组类型之前。例如,我们可以声明一个存储四个整数的数组,如下所示:
anArray := [4]int{1, 2, 4, -4}
在这个例子中,数组的大小被定义为4,而它存储的类型为int。如果需要获取数组的长度,可以使用len()函数:
len(anArray) // 输出:4
数组的索引从0开始,因此第一个元素的索引为0,第二个元素的索引为1,以此类推。这意味着,对于一个长度为n的数组,合法的索引范围是0到n-1。
虽然在其他编程语言中我们通常使用for循环和数字变量来遍历数组,但在Go语言中,更常见的做法是使用range关键字。这不仅使代码更加简洁,还能避免手动使用len()函数来确定数组长度。下面是一个使用range遍历数组的例子:
for index, value := range anArray {fmt.Println(index, value)
}
在这个例子中,range会返回数组元素的索引和对应的值。
多维数组
在Go语言中,数组可以有多个维度,常见的二维数组和三维数组在某些场景下十分有用。下面是如何声明二维数组和三维数组的例子:
twoD := [4][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}
threeD := [2][2][2]int{{{1, 0}, {-2, 4}}, {{5, -1}, {7, 0}}}
我们可以通过嵌套for循环来访问多维数组中的所有元素。例如,遍历三维数组的代码如下:
for i := 0; i < len(threeD); i++ {for j := 0; j < len(threeD[i]); j++ {for k := 0; k < len(threeD[i][j]); k++ {fmt.Print(threeD[i][j][k], " ")}fmt.Println()}
}
在上面的代码中,我们使用三层嵌套的for循环来遍历三维数组的每一个元素。每一层循环对应数组的一维。也可以使用更加简洁的range关键字来完成相同的操作:
for _, v := range threeD {for _, m := range v {for _, s := range m {fmt.Print(s, " ")}fmt.Println()}
}
这个方法更加简洁,且代码更加清晰,但range不会提供循环的索引值。如果需要索引,则依然需要使用传统的for循环。
数组的局限性
尽管数组在某些场景下有其优势,但它也存在许多缺点。首先,数组的长度在定义时就被固定,无法动态扩展。这意味着如果数组没有足够的空间来存储新元素,就必须创建一个更大的数组,并将旧数组的元素复制过去。此外,数组作为函数参数传递时,传递的是数组的副本,函数内部的任何修改在函数外部都不会生效。
以下是一个简单的例子,展示数组传递给函数时的副本行为:
func modifyArray(arr [4]int) {arr[0] = 99
}func main() {anArray := [4]int{1, 2, 4, -4}modifyArray(anArray)fmt.Println(anArray) // 输出仍然是:[1 2 4 -4]
}
这段代码中,anArray传递给modifyArray函数时,函数中修改的仅仅是数组的副本,原始数组未受影响。
另外,由于数组的大小固定,在传递大数组时,创建副本会占用大量内存和处理时间,导致效率低下。为了解决这些问题,Go语言提供了切片(Slices)这一更灵活且高效的数据结构。
切片的强大之处
Go语言的切片功能非常强大,可以完全取代大多数情况下数组的使用。与数组不同,切片是动态的,可以根据需要自动扩展。当将切片传递给函数时,传递的是切片的引用,而不是副本,这意味着函数内部的修改在函数外部依然有效。例如:
func modifySlice(slc []int) {slc[0] = 99
}func main() {aSlice := []int{1, 2, 4, -4}modifySlice(aSlice)fmt.Println(aSlice) // 输出:[99 2 4 -4]
}
在这个例子中,modifySlice函数修改了切片的第一个元素,由于切片是按引用传递的,因此修改在函数外部生效。
此外,传递切片比传递数组更加高效,因为切片的底层实现是指向底层数组的指针,而不是整个数组的副本。因此,切片不仅更加灵活,还提高了性能,尤其在处理大数据时。
通过对Go语言数组和切片的深入探讨,我们可以看到数组虽然简单易用,但由于其固定长度和传递副本的限制,在大多数情况下并不适合复杂的应用场景。而切片的动态性和传递引用的特性,使其成为处理动态数据的首选工具。在实际开发中,数组的使用场景较少,而切片几乎可以完全取代数组,成为开发者日常使用的数据结构。
通过合理使用切片,开发者可以编写更加灵活和高效的Go代码。希望通过本文的介绍,大家对Go语言的数组与切片有了更清晰的理解,并能够在实际开发中灵活运用这些知识。
深入理解Go语言切片操作
在Go语言中,切片(slice)是非常强大且灵活的数据结构。相比数组,切片提供了更多的功能,并且能够动态扩展。在本文中,我们将探讨如何对切片进行基本操作、切片的特性及其应用。
创建与初始化切片
你可以通过以下方式创建一个切片:
aSliceLiteral := []int{1, 2, 3, 4, 5}
这种方式类似于数组的定义,但没有指定元素的数量。如果你在定义中指定了元素数量,那么就不是切片,而是数组。另一个创建切片的方法是使用make()函数,这种方法允许你创建指定长度和容量的空切片:
integer := make([]int, 20)
需要注意的是,Go会自动将切片的元素初始化为其类型的零值。比如整型切片的零值是0。
切片的底层实际上是基于数组实现的,因此你可以通过索引访问其元素。例如,以下代码会输出切片中每个元素的值:
for i := 0; i < len(integer); i++ {fmt.Println(integer[i])
}
添加元素与重新切片
切片的大小可以动态增加。使用append()函数可以向切片添加元素,例如:
integer = append(integer, 12345)
你也可以通过索引访问切片的第一个和最后一个元素:
fmt.Println(integer[0]) // 访问第一个元素
fmt.Println(integer[len(integer)-1]) // 访问最后一个元素
切片的一个强大特性是可以使用[:]语法进行重新切片。下面的代码选取了切片中的第二个和第三个元素:
s2 := integer[1:3]
重新切片并不会创建切片的副本,而是引用相同的底层数组。因此,对重新切片的修改会影响原始切片:
s1 := make([]int, 5)
reSlice := s1[1:3]
reSlice[0] = -100
reSlice[1] = 123456
fmt.Println(s1) // 输出:[0 -100 123456 0 0]
fmt.Println(reSlice) // 输出:[-100 123456]
如上所示,修改reSlice中的元素实际上修改了s1中的元素,因为它们共享同一个底层数组。
切片的容量与自动扩展
切片有两个主要属性:长度和容量。长度表示切片当前元素的数量,而容量表示底层数组分配的空间。可以通过len()函数获取切片的长度,使用cap()函数获取其容量。切片的大小是动态扩展的,当空间不足时,Go会自动将容量翻倍。
下面是一个展示切片容量与长度变化的例子:
package main
import "fmt"func printSlice(x []int) {for _, number := range x {fmt.Print(number, " ")}fmt.Println()
}func main() {aSlice := []int{-1, 0, 4}printSlice(aSlice)fmt.Printf("容量: %d, 长度: %d\n", cap(aSlice), len(aSlice))aSlice = append(aSlice, -100)printSlice(aSlice)fmt.Printf("容量: %d, 长度: %d\n", cap(aSlice), len(aSlice))aSlice = append(aSlice, -2, -3, -4)printSlice(aSlice)fmt.Printf("容量: %d, 长度: %d\n", cap(aSlice), len(aSlice))
}
输出结果如下:
-1 0 4
容量: 3, 长度: 3
-1 0 4 -100
容量: 6, 长度: 4
-1 0 4 -100 -2 -3 -4
容量: 12, 长度: 7
你可以看到,当添加一个元素时,切片的长度增加,而容量则翻倍增长。
使用copy()函数复制切片
你可以使用copy()函数将一个切片的元素复制到另一个切片中。copy(dst, src)会将src切片中的元素复制到dst,并且只复制dst和src中较短的部分。例如:
a6 := []int{-10, 1, 2, 3, 4, 5}
a4 := []int{-1, -2, -3, -4}
copy(a6, a4)
fmt.Println(a6) // 输出:[-1 -2 -3 -4 4 5]
在这个例子中,a4的所有元素都被复制到a6,但a6的最后两个元素保持不变。
多维切片
切片不仅可以是一维的,还可以是多维的。例如,下面的代码创建了一个二维切片:
s1 := make([][]int, 4)
多维切片的元素也是切片,因此可以通过append()函数来初始化和扩展:
for i := 0; i < len(s1); i++ {for j := 0; j < 2; j++ {s1[i] = append(s1[i], i*j)}
}
使用sort.Slice()排序切片
Go提供了一个强大的sort.Slice()函数,用于根据指定的条件对切片进行排序。如下是一个简单的例子:
package main
import ("fmt""sort"
)type Person struct {name stringheight int
}func main() {people := []Person{{"张三", 180},{"李四", 175},{"王五", 160},}sort.Slice(people, func(i, j int) bool {return people[i].height < people[j].height})fmt.Println("升序:", people)sort.Slice(people, func(i, j int) bool {return people[i].height > people[j].height})fmt.Println("降序:", people)
}
运行结果:
升序: [{王五 160} {李四 175} {张三 180}]
降序: [{张三 180} {李四 175} {王五 160}]
总结
Go语言中的切片功能非常强大。它们不仅灵活且动态扩展,还可以通过append()、copy()等函数进行各种操作。切片比数组更适合大多数应用场景,尤其在处理动态数据时。通过掌握切片的这些特性,开发者可以编写出更高效、更灵活的Go语言程序。
相关文章:
深入探讨Go语言中的切片与数组操作
在编程世界中,数组一直是非常流行的数据结构,主要有两个原因:其一是简单易懂,其二是非常灵活,可以存储多种不同类型的数据。在Go语言中,数组的用法有其独特的特点,但与此同时,Go语言…...
【WPS Excel】复制表格时,提示“图片太大,超过部份将被截去“ 问题
WPS表格 2019版本 升级到 WPS最新版 WPS-支持多人在线协作编辑Word、Excel和PPT文档_WPS官方网站 使用最新版就能够解决这个问题,如果仍旧无法解决可以勾选如下配置 重启Excel解决。 请勾选:文件 - 选项 - 编辑 - 不提示且不压缩文件中的图像...
驱动(RK3588S)第九课时:多节点驱动与函数接口
目录 一、多节点概念1、所用到的结构体说明2、函数接口主要是read和write函数2.1、把应用层的数据拷贝给底层2.2、把应用层的数据拷贝给底层 3、应用层的read和write函数4、底层的read和write函数二、ioctl控制命令接口1、概念2、函数介绍应用层和驱动层 三、代码与现象1.编写L…...
Linux系统下配置MySQL
1. 寻找MySQL的配置文件 MySQL的配置文件通常位于以下位置: 在大多数Linux系统上,主配置文件通常位于/etc/mysql/my.cnf或/etc/my.cnf。在macOS上,如果你使用Homebrew安装MySQL,配置文件通常位于/usr/local/etc/my.cnf。在Window…...
信捷 XD PLC POU编程之FB
在使用信捷的POU方式编程,可以建立两种POU:FB和FC。 FB和FC这两种POU又各自可以建立梯形图语言POU和C语言POU。 函数块(FB)是把反复使用的部分程序块转换成一种通用部件,他可以在程序中反复被调用,不仅 提高了程序的开…...
终于有人把云计算、大数据和人工智能讲明白了!
引言 在当今数字化时代,云计算、大数据和人工智能成为了全球科技界的热门话题。这些技术的迅猛发展以及应用范围的不断扩大,正深刻地改变着我们的生活和工作方式。云计算为我们提供了有效的计算和存储能力,大数据则以海量的信息资源为基础&a…...
【编程底层思考】详解Java内存模型(JMM)原理及其作用
Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)的一个核心概念,它定义了Java程序中各种变量(线程共享变量)的访问规则,以及在并发环境下,为了确保数据的可见性、…...
Docker的基本概念和优势
Docker是一个开源的容器化平台,它可以将应用程序及其所有依赖项和运行环境打包到一个称为容器的独立单元中。容器化使得应用程序在不同的环境中可以以相同的方式运行,并且更加轻量级和可移植。 Docker的基本概念包括以下几点: 镜像…...
数据结构————内核链表
内核链表是Linux内核中广泛使用的一种数据结构,它具有以下特点: 1.双向循环链表:每个节点包含两个指针,一个指向前驱节点(prev),另一个指向后继节点(next),…...
使用API接口获取某宝商品数据详情
什么是淘宝API接口? 淘宝API接口是淘宝开放平台为开发者提供的一种应用程序接口。它允许开发者通过编程方式,安全、高效地与淘宝平台进行数据交互,从而获取商品详细信息、用户信息、订单信息等多种数据。这些接口不仅简化了数据获取流程&…...
用Python实现时间序列模型实战——Day 15: 时间序列模型的选择与组合
一、学习内容 1. 模型选择的标准与方法(如 AIC、BIC) 在时间序列建模中,模型的选择是非常重要的,常用的模型选择标准包括 AIC (Akaike Information Criterion) 和 BIC (Bayesian Information Criterion)。 AIC (Akaike Informat…...
大数据之Flink(五)
15、Flink SQL 15.1、sql-client准备 启用Hadoop集群(在Hadoop100上) start-all.sh启用yarn-session模式 /export/soft/flink-1.13.0/bin/yarn-session.sh -d启动sql-client bin/sql-client.sh embedded -s yarn-sessionsql文件初始化 可以初始化模式、环境(流/批…...
SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析
查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但…...
基于 jenkins 的持续测试方案
CI/CD Continuous Integration; Continuous Deployment; 持续集成,将新代码和旧代码一起打包、构建;持续部署,将新构建的包进行部署;持续测试,将新代码、新单元测试一起测试;方案: 公有云DevO…...
我算见识到算法岗transformer面试的难度了
在面试算法岗的时候看到了这篇Transformer面试题,作者梳理一些关于Transformer的知识点,还会陆续更新最新的面试题和讲解答案! 也算是见识到了transformer的面试难度了 1.Transformer为何使用多头注意力机制?(为什么不使用一个头) 2.Tra…...
CommonCollections1
CommonCollections1链 CommonCollections1poc展示调用链分析AbstractInputCheckedMapDecoratorTransformedMapChainedTransformerConstantTransformerInvokerTransformer poc分析通过反射实现Runtime.getRuntime().exec("calc.exe")forNamegetMethodinvoke 依据反射构…...
6、关于Medical-Transformer
6、关于Medical-Transformer Axial-Attention原文链接:Axial-attention Medical-Transformer原文链接:Medical-Transformer Medical-Transformer实际上是Axial-Attention在医学领域的运行,只是在这基础上增加了门机制,实际上也就…...
19_单片机开发常用工具的使用
工欲善其事必先利其器,我们做单片机开发的时候,不管是调试电路还是调试程序,都需要借助一些辅助工具来帮助查找和定位问题,从而帮助我们顺利解决问题。没有任何辅助工具的单片机项目开发很可能就是无法完成的任务,不过…...
最新版微服务项目搭建
一,项目总体介绍 在本项目中,我将使用alibabba的 nacos 作为项目的注册中心,使用 spring cloud gateway 做为项目的网关,用 openfeign 作为服务间的调用组件。 项目总体架构图如下: 注意:我的Java环境是17…...
spring揭秘19-spring事务01-事务抽象
文章目录 【README】【1】事务基本元素【1.1】事务分类 【2】java事务管理【2.1】基于java的局部事务管理【2.2】基于java的分布式事务管理【2.2.1】基于JTA的分布式事务管理【2.2.2】基于JCA的分布式事务管理 【2.3】java事务管理的问题 【3】spring事务抽象概述【3.1】spring…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
