5.go切片和map

news2025/4/21 16:45:16

切片的概念

数组和切片相比较切片的长度是不固定的,可以追加元素,在追加时可能会使切片的容量增大,所以可以将切片理解成 "动态数组",但是,它不是数组,而是构建在数组基础上的更高级的数据结构。

切片和数组的对比

  • 数组在声明时需要指定长度,切片不需要。

  • 数组的长度是数组类型的一部分,因此 [5]int 和 [10]int 是不同的类型,不能互相赋值或比较。而切片只需要考虑元素类型。

  • 数组是值类型,当数组作为参数传递时,会被复制一份,因此对数组的修改不会影响原数组。而切片是引用类型,当切片作为参数传递时,只会传递一个指向底层数组的指针,因此对切片的修改会影响原切片。

  • 数组的长度是固定的,在内存中占用连续的空间。而切片的长度是可变的,在内存中是一个结构体,其中包含指向底层数组的指针、长度和容量三个字段。

切片声明

  • 使用var声明切片

语法:var 切片名称[] 数据类型

var arr []int //此时变量arr 是切片的零值 [],和nil比较,是相等的。此时len是0,cap是0

  • 使用自动推导类型声明切片

语法:切片名称 := []类型{}

arr := []int{} //此时变量是指向一个长度为0的数组,和nil不等,此时len是0,cap是0

arr := []int{1,2,3} //此时变量是指向一个长度为3的数组,此时len是3,cap是3

  • 使用make()函数生成切片

语法:make([]类型, 长度, 容量)

长度是已初始化空间

容量是已经开辟空间,包括已经初始化的空间和空闲空间。

arr := make([]int, 3, 5)

fmt.Printf("长度:%d\t容量:%d", len(arr), cap(arr))

slice内存模型

例子:

a1 := make([]int, 1, 3) //此时a1被分配了长度是3,【a1[0,x,x]】

a2 := append(a1, 1, 2) //此时append 两个,底层数组可以容纳,【a2[0,1,2]】

a3 := append(a1, -1) //此时在a1的基础上[0,x,x],添加一个元素,底层数组可以容纳【a3[0,-1]】

//此时因为使用的是同一个数组,影响了a2,此时【a2[0,-1,2]】

fmt.Println(a1, a2, a3)

向切片中添加元素

arr := make([]int, 3, 5)

arr[0] = 100 //添加100

arr[1] = 200 // 添加200

//panic: runtime error: index out of range [3] with length 3

//arr[3] = 200 //错误,不能大于申请的长度

   //append可以在申请长度后边新增元素,如果不大于申请容量,直接放在在源底层数组上,

  //如果大于申请容量,会重新分底层配数组,把原来的数据拷贝到新数组上,然后在后边加上新元素

fmt.Println(arr)

append()函数切片添加元素

arr = append(arr, 1) // 追加1个元素

fmt.Printf("arr元素%v,arr长度%d,arr容量%d,arr地址%p\n", arr, len(arr), cap(arr), &arr[0])

arr = append(arr, 2, 3) // 最加多个元素

fmt.Printf("arr元素%v,arr长度%d,arr容量%d,arr地址%p\n", arr, len(arr), cap(arr), &arr[0])

arr = append(arr, []int{5, 6, 7}...) // 追加一个切片

fmt.Printf("arr元素%v,arr长度%d,arr容量%d,arr地址%p\n", arr, len(arr), cap(arr), &arr[0])

注意:在使用 append() 函数为切片动态添加元素时,如果空间不足以容纳足够多的元素,切片就会进行“扩容”,此时新切片的长度会发生改变,会导致内存的重新分配,而且已有元素全部被复制 1 次到新分配的内存地址上。

... 运算符将切片展开为多个独立的参数

var arr = []int{1, 2, 3}

fmt.Printf("arr元素%v,arr长度%d,arr容量%d,arr[0]地址%p\n", arr, len(arr), cap(arr), &arr[0])

arr = append([]int{666}, arr...) // 定义一个新切片,并且把原来切片展开,添加到新切片里

fmt.Printf("arr元素%v,arr长度%d,arr容量%d,arr[0]地址%p\n", arr, len(arr), cap(arr), &arr[0])

内存分析

//此时,内存进行了三次分配,首先定义的a,会分配一个数量是3的底层数组,

// 定义[]int{666},时候,会分配一个数量是1的底层数组,

//往[]int{666} 添加切片时候,空间不够,会在开辟一块底层是4的数组,

//然后 拷贝[]int{666}到新数组,在拷贝a切片内容到新数组,最后把a切片底层指向数组的指针指向新分配的数组

copy()函数复制切片

Go语言的标准库提供了一个非常方便的copy函数,它可以用来复制切片(slice)或者数组(array)中的内容。

copy( destSlice, srcSlice)

  • srcSlice:数据来源切片

  • destSlice:复制的目标

在使用 copy 函数时,需要确保源切片和目标切片的长度相同

如果长度不同,copy 函数只会复制较短切片的长度。这可能导致数据丢失或意外的行为。

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

dst := make([]int, 3)

n := copy(dst, src) // n 将等于 3,而不是 5

遍历切片

arr := make([]int, 3, 5)

arr = append(arr, 200, 300)

// // 传统for循环

// for i := 0; i < len(arr); i++ {

// fmt.Println(arr[i])

// }

// for range遍历

for _, v := range arr {

fmt.Println(v)

}

子切片

  子切片是指在Go语言中,从一个已有的切片中创建出的一个新的切片。子切片与原始切片共享同一个底层数组,但拥有自己的长度和容量。因为子切片共享原切片的底层数组,因此对数据的更改会影响彼此。

  子切片写法

  切片[startIndex:endIndex]

  startIndex 是子切片的起始索引,endIndex 是子切片的结束索引(但不包括该索引处的元素)。

  如果省略 startIndex(切片[startIndex:]),则从切片的开始处截取;

  如果省略 endIndex(切片[:endIndex]),则截取到切片的末尾。

  如果都省略(切片[:]),则截取原切片全部。

  例子:

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

  sub := s[1:4] // 创建从索引1到索引3的子切片,

  fmt.Println(sub) // 输出:[2 3 4]

  sub[0] = 20 // 修改sub的第一个元素

  fmt.Println(s) // 输出:[1 20 3 4 5],s也被修改

sub = append(sub, 300)

fmt.Println(s) // 输出:[1 20 3 4 300],底层分配的数组,后边还有未使用

  //,所以不会扩容,会在原来底层数组上做修改

map

在Go语言中,map 类型是一个内置的引用类型,它存储键值对(key-value pairs)。map 是由一个键类型和一个值类型构成的,其中键的类型必须是可比较的(例如,整型、字符串、结构体等,但不能是切片或函数等不可比较的类型)。

map 零值是 nil 。不能直接使用,需要make创建 或者 字面量赋值

var m map[string]int m["apple"] = 1 //错误:panic: assignment to entry in nil map

创建 map

你可以使用 make 函数或者使用字面量语法来创建一个 map

  • 使用 make 函数:

  • 使用字面量语法:

m := map[string]int{
    "apple":  5,
    "pear":   6,
    "grape":  8,
}

访问 map 中的元素

你可以通过键来访问 map 中的元素。如果键存在,它将返回对应的值;如果键不存在,它将返回零值(对于值类型)或者一个明确的错误。

value, ok := m["apple"] // value 为 5, ok 为 true value, ok = m["banana"] // value 为 0 (int 的零值), ok 为 false

修改 map 中的元素

你可以通过键来修改 map 中的元素。如果键存在,它的值将被更新;如果键不存在,一个新的键值对将被添加到 map 中。

m["apple"] = 10 // 将 "apple" 的值改为 10 m["banana"] = 3 // 添加一个新的键值对 "banana": 3

删除 map 中的元素

你可以使用 delete 函数来删除 map 中的元素。

delete(m, "apple") // 删除键为 "apple" 的元素

遍历 map

你可以使用 range 循环来遍历 map 中的所有键值对。在每次迭代中,range 会返回两个值:键和对应的值。

for key, value := range m { fmt.Println(key, value) }

map 的并发访问和修改

从Go 1.9开始,map 是并发安全的,你可以在多个goroutine中安全地读写同一个map。但是,如果你需要频繁地修改同一个map,最好还是限制对它的并发访问,以避免不必要的性能开销。如果你确实需要频繁地并发修改,可以考虑使用 sync.Map,它是专门为并发环境设计的。

注意事项

  • 零值:当你声明了一个 map 变量但没有初始化(即没有用 make 或字面量语法),它的零值是 nil。尝试在 nilmap 上进行读写操作将会导致运行时恐慌(panic)。因此,在使用前应确保 map 被正确初始化。

  • 并发安全:虽然Go的map在1.9版本后是并发安全的,但在高并发的场景下仍可能遇到性能瓶颈或需要更精细的控制,这时可以考虑使用 sync.Map

  • 性能考虑:虽然Go的map提供了很好的性能和灵活性,但在某些特定情况下(如频繁的删除操作),可能需要考虑其性能影响或选择其他数据结构(如平衡树)。

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

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

相关文章

【Linux网络-多路转接select】

代码&#xff1a;https://gitee.com/nanyi-c/linux/tree/master/day50 一、I/O多路转接之select 1.初始select 系统提供select函数来实现多路复用输入/输出模型 select系统调用是用来让我们的程序监视多个文件描述符的状态变化的程序会停在select这里等待&#xff0c;直到被…

cmd命令查看电脑的CPU、内存、存储量

目录 获取计算机硬件的相关信息的命令分别的功能结果展示结果说明获取计算机硬件的相关信息的命令 wmic cpu get name wmic memorychip get capacity wmic diskdrive get model,size,mediaType分别的功能 获取计算机中央处理器(CPU)的名称 获取计算机内存(RAM)芯片的容量…

LVS的 NAT 模式实现 3 台RS的轮询访问

使用LVS的 NAT 模式实现 3 台RS的轮询访问 1.配置 RS&#xff08;NAT模式&#xff09;2. 配置 LVS 主机&#xff08;仅主机、NAT模式&#xff09;2.1 配置仅主机网卡&#xff08;192.168.66.150/24 VIP &#xff09;2.2 配置 NAT 网卡&#xff08;192.168.88.6/24 DIP&#xff…

phpcms版AI自动发文插件,自动创作,自动配图,自动发布,支持多种大模型

phpcms版本的AI自动发文插件1.0.0版&#xff0c;支持自动写文章&#xff0c;自动配图&#xff0c;自动发布。目前支持DeepSeek&#xff0c;豆包&#xff0c;通义千问&#xff0c;文心一言&#xff0c;讯飞星火&#xff0c;KIMI&#xff0c;腾讯混元登大模型AI。同时有自定义字段…

C语言判断闰年相关问题

一、简单闰年问题引入 写一个判断年份是否为闰年的程序? 运行结果: 二、闰年问题进阶 使用switch语句根据用户输入的年份和月份,判断该月份有多少天? 第一种写法(判断年份写在switch的case的里面): 运行结果: 第二种解法(先判断闰年): 运行结果: 三、补充 switch中的ca…

数模转换电路(D/A转换器)

将数字信号转换成模拟信号称为数/模转换, 简称D/A&#xff08;Digital to Analog&#xff09;转换&#xff0c;实现 D/A 转换的器件称为D/A转换器&#xff0c;简称 DAC&#xff08;Digital-Analog Converter&#xff09;。 将模拟信号转换成数字信号称为模/数转换, 简称A/D&a…

网络基础-路由器和交换机工作配置

三、路由器和交换机的工作原理配置以及华为体系下的小型网络的搭建 3.1路由基础 3.1.1数据转发 通过链路层交换机和网络层路由器进行数据转发 交换机&#xff08;链路层&#xff09;mac地址表的数据转发路由器&#xff08;网络层&#xff09; ip路由表的数据转发 隔离广播域…

uv包简单使用案例

uv由Charlie Marsh开发&#xff0c;是Astral Tool的一个快速Python包安装器和解析器。它类似于pip和pip-tools&#xff0c;但速度更快。此外&#xff0c;uv还支持虚拟环境管理&#xff0c;替代venv和virtualenv。 参考&#xff1a;https://github.com/astral-sh/uv 安装&#x…

JAVA学习*String类

String类 基本知识 String类的构造方法 String类的构造方法有很多&#xff0c;我们需要掌握常见的构造方法&#xff0c;来赋初识值。 1、new一个String类的对象 String name new String("张三");2、使用字符串常量进行赋值 String name "张三";相当…

Java IO框架体系深度解析:从四基类到设计模式实践

Java IO框架体系深度解析&#xff1a;从四基类到设计模式实践 一、IO流体系架构总览 1.1 四基类设计哲学 Java IO框架以InputStream、OutputStream、Reader、Writer四个抽象类为根基&#xff0c;构建了完整的流式IO体系。这种设计体现了以下核心原则&#xff1a; 抽象分层&a…

【读书笔记】华为《从偶然到必然》

note 华为的成功并非偶然&#xff0c;而是通过IPD体系、投资组合管理、平台战略等系统性工具&#xff0c;将研发投资转化为可持续的商业竞争力。书中强调的“管理即内部因素”理念&#xff0c;揭示了企业规模扩张与管理能力匹配的深层规律&#xff0c;为高科技企业提供了可借鉴…

failed to load steamui.dll”错误:Steam用户的高频崩溃问题解析

当你满心欢喜地双击 Steam 图标&#xff0c;准备进入游戏世界时&#xff0c;屏幕上突然弹出 “failed to load steamui.dll” 的刺眼提示——这是全球数百万 Steam 用户最不愿见到的错误之一。作为 Steam 客户端的核心界面动态链接库文件&#xff0c;steamui.dll 的缺失或损坏会…

Linux多线程详解

Linux多线程详解 一、Linux多线程概念1.1 什么是线程1.2 进程和线程1.3 进程的多个线程共享1.4 进程和线程的关系 二、Linux线程控制2.1 POSIX线程库2.2 线程创建2.3 获取线程ID pthread_self2.4 线程等待pthread_join2.5 线程终止2.6 线程栈 && pthread_t2.7 线程的局…

权限提升—Windows权限提升土豆家族溢出漏洞通杀全系

前言 OK&#xff0c;Java安全更新不下去了&#xff0c;实在是太难啦啊&#xff0c;想起来提权这一块没怎么更新过&#xff0c;接下来都主要是更新提权这一块的文章了&#xff0c;Java安全的话以后有耐心再搞了。 手动提权 今天主要是讲这个手动的提权&#xff0c;手动提权相…

JVM(基础篇)

一.初识JVM 1.什么是JVM JVM全称Java Virtyal Machine&#xff0c;中文译名 Java虚拟机 。JVM本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件(将字节码解释成机器码)。 2.JVM的功能 解释和运行&#xff1a;对字节码文件中的指令号&#xff0c;实时…

【Unity网络编程知识】使用Socket实现简单TCP通讯

1、Socket的常用属性和方法 创建Socket TCP流套接字 Socket socketTcp new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 1.1 常用属性 1&#xff09;套接字的连接状态 socketTcp.Connected 2&#xff09;获取套接字的类型 socketTcp.So…

【深度学习】GAN生成对抗网络:原理、应用与发展

GAN生成对抗网络&#xff1a;原理、应用与发展 文章目录 GAN生成对抗网络&#xff1a;原理、应用与发展1. 引言2. GAN的基本原理2.1 核心思想2.2 数学表达2.3 训练过程 3. GAN的主要变体3.1 DCGAN (Deep Convolutional GAN)3.2 CGAN (Conditional GAN)3.3 CycleGAN3.4 StyleGAN…

Live555+Windows+MSys2 编译Androidso库和运行使用(二,实验篇)

文章目录 实验下载推流服务端版本运行 摘要&#xff1a;书接上回 https://blog.csdn.net/qq_20330595/article/details/146412411?spm1001.2014.3001.5502 我们先做几个试验&#xff0c;方便我们理解rtsp推流&#xff0c;先把采集和播放体验一下&#xff0c;我们最后回到代码…

工作杂谈(十七)——研发阶段术语

EVT/DVT/PVT/MP是指在制造行业一个产品研发导入从试产到量产的不同阶段&#xff1a;   EVT&#xff1a;Engineering Verification Test工程验证测试阶段   DVT&#xff1a;Design Verification Test设计验证测试   PVT&#xff1a;Production Verification Test 小批量生…

2025 polarctf春季个人挑战赛web方向wp

来个弹窗 先用最基础的xss弹窗试一下 <script>alert("xss")</script>没有内容&#xff0c;猜测过滤了script&#xff0c;双写绕过一下 <scrscriptipt>alert("xss")</scscriptript>background 查看网页源代码 查看一下js文件 类…