三 Go的语言容器
1. 数组
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在Go语言中很少直接使用数组
声明语法:
var 数组变量名 [元素数量]Type
package main
import ("fmt"
)
func main() {var a [3]int // 定义三个整数的数组,仅是定义,默认值是填0fmt.Println(a[0]) // 打印第一个元素fmt.Println(a[len(a)-1]) // 打印最后一个元素// 打印索引和元素for i, v := range a {fmt.Printf("%d %d\n", i, v)}for _, v := range a {fmt.Printf("%d\n", v)}var q = [...]int{1, 2, 3}var r = [3]int{1, 2}fmt.Println(q[1]) // "2"fmt.Println(r[2]) // "0"k := [...]int{1, 2, 3}v := [...]int{2, 3, 4}//m := [...]int{1, 2, 3, 4}fmt.Println(k == v) //false//fmt.Println(k == m) //不同类型无法进行比较var teams [3]stringteams[0] = "hello"teams[1] = "go"teams[2] = "!"for i, v := range teams {fmt.Printf("序号: %d 值: %s\n", i, v)}
}
2. 切片
2.1 定义切片
// 声明字符串切片
var strList []string
// 声明整型切片
var numList []int
// 声明一个空切片
var numListEmpty = []int{}
// 输出3个切片
fmt.Println(strList, numList, numListEmpty)
// 输出3个切片大小
fmt.Println(len(strList), len(numList), len(numListEmpty))
// 切片判定空的结果
fmt.Println(strList == nil)
fmt.Println(numList == nil)
fmt.Println(numListEmpty == nil)
make构造切片
a := make([]int, 2)
b := make([]int, 2, 10)
fmt.Println(a, b)
fmt.Println(len(a), len(b))
2.2 为切片新增元素
package main
import "fmt"
var numbers []int
func main() {var a []intx := []int{1, 2, 3}a = append(a, 1) // 追加1个元素a = append(a, 1, 2, 3) // 追加多个元素, 手写解包方式a = append(a, x...) // 追加一个切片, 切片需要解包fmt.Println(a)deal()var b = []int{1, 2, 3}b = append([]int{0}, b...) // 在开头添加1个元素fmt.Println(b)b = append([]int{-3, -2, -1}, b...) // 在开头添加1个切片fmt.Println(b)
}
func deal() {for i := 0; i < 10; i++ {numbers = append(numbers, i)fmt.Printf("len: %d cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)}
}
2.3 切片复制
copy作用前面的切片元素,以小的切片元素为复制对象
package main
import "fmt"
func main() {slice1 := []int{1, 2, 3, 4, 5}slice2 := []int{5, 4, 3}copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中fmt.Println(slice1) //[1 2 3 4 5]fmt.Println(slice2) //[1 2 3]slice2 = []int{7, 8, 9}copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置fmt.Println(slice1) //[7 8 9 4 5]
}
package main
import "fmt"
func main() {// 设置元素数量为1000const elementCount = 1000// 预分配足够多的元素切片srcData := make([]int, elementCount)// 将切片赋值for i := 0; i < elementCount; i++ {srcData[i] = i}// 引用切片数据refData := srcData// 预分配足够多的元素切片copyData := make([]int, elementCount)// 将数据复制到新的切片空间中copy(copyData, srcData)// 修改原始数据的第一个元素srcData[0] = 999// 打印引用切片的第一个元素fmt.Println(refData[0])// 打印复制切片的第一个和最后一个元素fmt.Println(copyData[0], copyData[elementCount-1])// 复制原始数据从4到6(不包含)copy(copyData, srcData[4:6])for i := 0; i < 5; i++ {fmt.Printf("%d ", copyData[i])}
}
代码说明如下:
- 第 8 行,定义元素总量为 1000。
- 第 11 行,预分配拥有 1000 个元素的整型切片,这个切片将作为原始数据。
- 第 14~16 行,将 srcData 填充 0~999 的整型值。
- 第 19 行,将 refData 引用 srcData,切片不会因为等号操作进行元素的复制。
- 第 22 行,预分配与 srcData 等大(大小相等)、同类型的切片 copyData。
- 第 24 行,使用 copy() 函数将原始数据复制到 copyData 切片空间中。
- 第 27 行,修改原始数据的第一个元素为 999。
- 第 30 行,引用数据的第一个元素将会发生变化。
- 第 33 行,打印复制数据的首位数据,由于数据是复制的,因此不会发生变化。
- 第 36 行,将 srcData 的局部数据复制到 copyData 中。
- 第 38~40 行,打印复制局部数据后的 copyData 元素。
2.4 切片删除元素
2.4.1 开头元素
特性
a := []int{1, 2, 3}
a = a[1:] // 删除开头1个元素
a = a[N:] // 删除开头N个元素
append
a = []int{1, 2, 3}
a = append(a[:0], a[1:]...) // 删除开头1个元素
a = append(a[:0], a[N:]...) // 删除开头N个元素
copy
a = []int{1, 2, 3}
a = a[:copy(a, a[1:])] // 删除开头1个元素
a = a[:copy(a, a[N:])] // 删除开头N个元素
2.4.2 中间删除
a = []int{1, 2, 3, ...}
a = append(a[:i], a[i+1:]...) // 删除中间1个元素
a = append(a[:i], a[i+N:]...) // 删除中间N个元素
a = a[:i+copy(a[i:], a[i+1:])] // 删除中间1个元素
a = a[:i+copy(a[i:], a[i+N:])] // 删除中间N个元素
2.4.3 末尾删除
a := []int{1, 2, 3}
a = a[:len(a)-1] // 删除尾部1个元素
a = a[:len(a)-N] // 删除尾部N个元素
2.4.4 指定元素删除
package main
import "fmt"
func main() {list1 := []int{1, 2, 3, 3, 5, 4}list2 := []int{1, 2, 3, 3, 5, 4}list1 = DeleteSlice3(list1, 3)fmt.Println(list1)list3 := DeleteSlice2(list2, 3)fmt.Println(list3)
}
// DeleteSlice3 位移法
func DeleteSlice3(a []int, elem int) []int {j := 0for _, v := range a {if v != elem {a[j] = vfmt.Println(a)j++}}return a[:j]
}
// DeleteSlice2 拷贝法
func DeleteSlice2(a []int, elem int) []int {tmp := make([]int, 0, len(a))for _, v := range a {if v != elem {tmp = append(tmp, v)}}return tmp
}位移法输出:
[1 2 3 3 5 4]
[1 2 3 3 5 4]
[1 2 5 3 5 4]
[1 2 5 4 5 4]
[1 2 5 4]解析:把后面不等于3的元素提前,然后根据最后j的长度来返回需要取多长,同时把3元素排除拷贝法输出:
[1]
[1 2]
[1 2 5]
[1 2 5 4]
[1 2 5 4]
解析:这个就很好理解了,创建一个空的切片,值不等就添加进去
3. 映射
3.1 map概念
package main
import "fmt"
func main() {map1 := make(map[int]int)map1 = map[int]int{1: 3, 2: 4}fmt.Println(map1)for i, v := range map1 {fmt.Printf("键是: %d 值是: %d\n", i, v)}
}
3.2 遍历map
package main
import "fmt"
func main() {slice1 := make([]int, 0)slice1 = append(slice1, 1, 2, 3, 4)map1 := make(map[int]int)for i, v := range slice1 {map1[i] = v}fmt.Println(map1)
}注明:
for i, v := range 可输出键值
如果只需要键:
for i := range
如果只需要值:
for _, v := range
3.3 map转slice排序
package main
import ("fmt""sort"
)
func main() {scene := make(map[string]int)// 准备map数据scene["route"] = 66scene["brazil"] = 4scene["china"] = 960// 声明一个切片保存map数据var sceneList []string// 将map数据遍历复制到切片中for k := range scene {sceneList = append(sceneList, k)}// 对切片进行排序sort.Strings(sceneList) //对字符串进行排序// 输出fmt.Println(sceneList)
}
3.4 删除map中的元素
package main
import ("fmt"
)
func main() {scene := make(map[string]int)// 准备map数据scene["route"] = 66scene["brazil"] = 4scene["china"] = 960delete(scene, "brazil")for k, v := range scene {fmt.Println(k, v)}
}
ps: 使用字典就是用make函数重新创个新的即可,其余的交给GC回收机制
3.5 并发环境使用Map
sync.Map 有以下特性:
- 无须初始化,直接声明即可。
- sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。
- 使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。
代码演示如下:
package main
import ("fmt""sync"
)
func main() {var scene sync.Map// 将键值对保存到sync.Mapscene.Store("greece", 97)scene.Store("london", 100)scene.Store("egypt", 200)// 从sync.Map中根据键取值fmt.Println(scene.Load("london"))// 根据键删除对应的键值对scene.Delete("london")// 遍历所有sync.Map中的键值对scene.Range(func(k, v interface{}) bool {fmt.Println("iterate:", k, v)return true})
}
代码说明如下:
- 第 10 行,声明 scene,类型为 sync.Map,注意,sync.Map 不能使用 make 创建。
- 第 13~15 行,将一系列键值对保存到 sync.Map 中,sync.Map 将键和值以 interface{} 类型进行保存。
- 第 18 行,提供一个 sync.Map 的键给 scene.Load() 方法后将查询到键对应的值返回。
- 第 21 行,sync.Map 的 Delete 可以使用指定的键将对应的键值对删除。
- 第 24 行,Range() 方法可以遍历 sync.Map,遍历需要提供一个匿名函数,参数为 k、v,类型为 interface{},每次 Range() 在遍历一个元素时,都会调用这个匿名函数把结果返回。
4. 列表
列表创建与传值
package main
import ("container/list""fmt"
)
func main() {l := list.New()l.PushFront("hello")l.PushBack("world")element := l.PushBack("wo")l.InsertBefore("baby", element)l.InsertAfter("aiNi", element)l.Remove(element)for i := l.Front(); i != nil; i = i.Next() {fmt.Println(i.Value)}
}
5. 空值与零值
指针、切片、映射、通道、函数和接口的零值则是 nil
5.1 nil标识符不能比较
package main
import ("fmt"
)
func main() {fmt.Println(nil==nil)
}
运行结果: 未定义操作
PS D:\code> go run .\main.go
#command-line-arguments
.\main.go:8:21: invalid operation: nil == nil (operator == not defined on nil)
5.2 nil不是关键字和保留字
以下编写是可以通过编译的,但不推荐这么做
var nil = errors.New("my god")
5.3 nil没有默认类型
package main
import ("fmt"
)
func main() {fmt.Printf("%T", nil)print(nil)
}
输出:
#command-line-arguments
.\main.go:7:8: use of untyped nil in argument to print
5.4 不同类型 nil 的指针是一样的
package main
import ("fmt"
)
func main() {var arr []intvar num *intfmt.Printf("%p\n", arr)fmt.Printf("%p", num)
}
输出:
0x0
0x0
Process finished with the exit code 0
5.5 nil是map、slice、pointer、channel、func、interface 的零值
package main
import ("fmt"
)
func main() {var m map[int]stringvar ptr *intvar c chan intvar sl []intvar f func()var i interface{}fmt.Printf("%#v\n", m)fmt.Printf("%#v\n", ptr)fmt.Printf("%#v\n", c)fmt.Printf("%#v\n", sl)fmt.Printf("%#v\n", f)fmt.Printf("%#v\n", i)
}
输出:
PS D:\code> go run .\main.go
map[int]string(nil)
(*int)(nil)
(chan int)(nil)
[]int(nil)
(func())(nil)
5.6 不同类型的nil值占用的内存大小可能不一样
package main
import ("fmt""unsafe"
)
func main() {var p *struct{}fmt.Println( unsafe.Sizeof( p ) ) // 8var s []intfmt.Println( unsafe.Sizeof( s ) ) // 24var m map[int]boolfmt.Println( unsafe.Sizeof( m ) ) // 8var c chan stringfmt.Println( unsafe.Sizeof( c ) ) // 8var f func()fmt.Println( unsafe.Sizeof( f ) ) // 8var i interface{}fmt.Println( unsafe.Sizeof( i ) ) // 16
}
输出:
PS D:\code> go run .\main.go
8
24
8
8
8
16
相关文章:
三 Go的语言容器
1. 数组 数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在Go语言中很少直接使用数组 声明语法: var 数组变量名 [元素数量]Typepackage main import ("fmt" ) fu…...
2023年全国最新会计专业技术资格精选真题及答案16
百分百题库提供会计专业技术资格考试试题、会计考试预测题、会计专业技术资格考试真题、会计证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 一、单选题 1.下列各项关于会计监督职能的表述中,正确的是ÿ…...
模板进阶(仿函数,特化等介绍)
非类型模板参数 模板参数有类型形参和非类型形参; 类型形参:使用typename或者class修饰的参数类型名称 非类型形参:一个普通常量作为模板参数形参,不能为浮点数,字符类型以及类对象; #include<iostrea…...
Beats:在 Docker 中同时部署 Metricbeat 和 Elasticsearch
在本教程中,我们将部署一个 metricbeat 来监控正在运行的容器的健康状况和系统指标。 为什么需要监控,为什么需要 Metricbeat? 一个常见的问题,但很少有人回答。 首先,无论我们部署的是 docker 容器还是老式的金属箱&…...
编码技巧——Redis Pipeline
本文介绍Redis pipeline相关的知识点及代码示例,包括Redis客户端-服务端的一次完整的网络请求、pipeline与client执行多命令的区别、pipeline与Redis"事务"、pipeline的使用代码示例; pipeline与client执行多命令的区别 Redis是一种基于客户…...
ArcGIS制图技巧:制图入门与点、线、面状符号制作
目的: 1、了解地图制作目的; 2、了解在ArcMap平台中制作地图大致过程。 3、掌握地形图生成的操作; 4、掌握地形图的正确输出方法。 5、理解点状符号、线状符号、面状符号的基本概念; 6、理解地形点状符号、线状符号、面状符…...
Java基础 关于字典数据维护接口设计
开发环境 Eclipse2022JDK1.8 目录 1. 概述 2. 实现步骤 2.1 定义通用接口 2.2 定义实体类 2.3 接口扩展 2.4 接口实现 2.5 功能测试 3. 结语 1. 概述 每一个信息系统或多或少都带有一些数据字典,在维护上,基本上分为增删改查,也就是对数据…...
从零开始学架构——复杂度来源
复杂度来源——高性能 对性能孜孜不倦的追求是整个人类技术不断发展的根本驱动力。例如计算机,从电子管计算机到晶体管计算机再到集成电路计算机,运算性能从每秒几次提升到每秒几亿次。但伴随性能越来越高,相应的方法和系统复杂度也是越来越高。现代的计算机CPU集成…...
什么时候需要分表分库?
在当今互联网时代,海量数据基本上是每一个成熟产品的共性,特别是在移动互联网产品中,几乎每天都在产生数据,例如,商城的订单表、支付系统的交易明细以及游戏中的战报等等。对于一个日活用户在百万数量级的商城来说&…...
冰刃杀毒工具使用实验(29)
实验目的 (1)学习冰刃的基本功能; (2)掌握冰刃的基本使用方法;预备知识 windows操作系统的基本知识,例如:进程、网络、服务和文件等的了解。 冰刃是一款广受好评的ARK工…...
聊聊图像分割的DICE和IOU指标
目录 1. 介绍 2. dice 和 iou 的联系 3. 代码实现 3.1 dice 3.2 iou 3.3 test 3.4 dice 和 iou 的关系曲线 4. 代码 1. 介绍 dice 和 iou 都是衡量两个集合之间相似性的度量 dice计算公式: iou计算公式: iou的集合理解: iou 其实就…...
软件设计师教程(十)计算机系统知识-结构化开发
软件设计师教程 软件设计师教程(一)计算机系统知识-计算机系统基础知识 软件设计师教程(二)计算机系统知识-计算机体系结构 软件设计师教程(三)计算机系统知识-计算机体系结构 软件设计师教程(…...
链表OJ之 快慢指针法总结
欢迎来到 Claffic 的博客 💞💞💞 前言: 快慢指针指的是每次指针移动的步长,是解决链表相关的题目的一大利器,下面我将以例题的形式讲解快慢指针法。 目录 一. 链表的中间结点 思路: 代码实…...
C++STL详解(五)——list的介绍与使用
文章目录list的介绍list的使用list的定义方法list迭代器失效问题list插入和删除inserteraselist迭代器的使用begin,end 和 rbegin,rendlist元素访问front 和 backlist容量控制与数据清理resizeclearlist操作函数spliceremove 和 remove_ifuniquemergerev…...
进程和进程的调度
今天,为大家带来进程和进程的调度的学习 1.认识计算机 2.什么是操作系统 3.什么是进程 4.进程管理 5.进程的属性 6.进程的调度 7.进程调度的过程 8.内存分配 1.认识计算机 计算机的组成有五大部分 1.CPU(是计算机的大脑,负责逻辑运算和控制) 2.内存 3.外存 4.输入…...
TypeScript 深度剖析:TypeScript 的理解?与 JavaScript 的区别?
一、是什么 TypeScript 是 JavaScript 的类型的超集,支持ES6语法,支持面向对象编程的概念,如类、接口、继承、泛型等 超集,不得不说另外一个概念,子集,怎么理解这两个呢,举个例子,如…...
美颜SDK关键技术讲解——人脸识别与人脸美化
拍摄,自从智能手机普及之后就已经不再是小众爱好,使用手机拍摄记录生活几乎成了人们的日常。在巨量的需求下,美颜工具、美颜SDK已经被广泛应用于各大视频拍摄平台。虽然经常听到美颜SDK,但是大多数人并不了解它,下文小…...
Linux下C/C++ 网络扫描(主机扫描技术)
主机扫描是网络扫描的基础,通过对目标网络中主机IP地址的扫描,从一堆主机中扫描出存活的主机,然后以他们为目标进行后续的攻击。一般会借助于ICMP、TCP、UDP等协议的工作机制,检查打开的进程,开放的端口号等等。 主机…...
无法将“vue-cli-service”项识别为 cmdlet、函数、脚本文件或不是内部命令的原因和解决方案
经常有小伙伴问我说,为什么我们在开发vue项目的时候,需要在package.json的script对象中,去设置命令启动项目,而不是直接的通过"vue-cli-service serve"命令去把项目跑起来。带着这些疑问,小生在此总结了以下…...
逆流程 场景下 处理状态机变化的方案
背景: 针对某些业务场景下,存在逆流程。 比如场景的场景 正向流程如,发起某项申请->对某项申请进行审批。(审批为通过/驳回)。这样这个工作流程就算到最终态。 常见的状态机如, 申请未提交࿰…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
