三 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"命令去把项目跑起来。带着这些疑问,小生在此总结了以下…...
逆流程 场景下 处理状态机变化的方案
背景: 针对某些业务场景下,存在逆流程。 比如场景的场景 正向流程如,发起某项申请->对某项申请进行审批。(审批为通过/驳回)。这样这个工作流程就算到最终态。 常见的状态机如, 申请未提交࿰…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
