Go map详解和实战

简介: 今天继续为大家更新Go语言学习记录的文章

声明map


和切片的定义一样,我们定义map未进行初始化时,map==nil。 map和切片一样,也是引用类型,不是值类型。


var m1 map[string]int  //声明
fmt.Println(m1 == nil) //返回true  


没有初始化,说明没有在内存中开辟空间,没有内存地址


初始化


map的初始化一定要先声明,再初始化;不能直接初始化,否则会报错:undefined


var m1 map[string]int
m1 = make(map[string]int, 10) //要估算好map的容量,避免在程序运行期间在动态扩容(动态扩容会影响程序运行效率)
m1["lucky"] = 18
m1["jason"] = 24
fmt.Println(m1)


打印结果:


微信图片_20221112152035.jpg


注意:要估算好map的容量,避免在程序运行期间再动态扩容(动态扩容会影响程序运行效率)

也可以使用:=简化,代表声明并初始化。


我们把上面的代码简化一下:


//简化 := 表示声明并初始化
m1 := make(map[string]int,10)
m1["lucky"] = 18
m1["jason"] = 24
fmt.Println(m1)


打印结果:


微信图片_20221112152039.jpg


我们发现结果是一样的。

开发过程中我们根据场景来判断使用哪种方式来进行声明、初始化操作。


取值


取值非常简单 map[key] 的方式就能取值了,例如


fmt.Println(m1["jason"])
fmt.Println(m1["jason1"]) //map查询不存在的key也不会报错 返回了空值


打印结果:


微信图片_20221112152042.jpg


注意:map查询不存在的key不会报错的,返回了空值。


取值判断


上面提到了map查询不存在的key值也不会报错,而是返回了空值。

我们如何判断取到的值是否为空值呢?

建议大家map取值的时候这么写


value,ok := m1["jason1"]
if ok {
   fmt.Println(value)
}else {
   fmt.Println("不存在")
}


打印结果:


微信图片_20221112152045.jpg


遍历取值


取出键值对


for k, v := range m1 {
   fmt.Println(k,v)
}


打印结果:


微信图片_20221112152049.jpg


只取键


for k := range m1 {
   fmt.Println(k)
}


打印结果:


微信图片_20221112152052.jpg


只取值


for _, v := range m1 {
   fmt.Println(v)
}


打印结果:


微信图片_20221112152055.jpg


删除 delete()


map的删除很简单,内置了delete函数;

不像切片移除元素那么复杂,切片移除元素只能通过分割+append的方式。


var m1 map[string]int
m1 = make(map[string]int, 10)
m1["lucky"] = 18
m1["jason"] = 24
fmt.Println(m1)
delete(m1,"jason")
fmt.Println(m1)


打印结果:


微信图片_20221112152059.jpg


删除不存在的key


删除不存在的key,也不会报错。


var m1 map[string]int
m1 = make(map[string]int, 10)
m1["lucky"] = 18
m1["jason"] = 24
fmt.Println(m1)
fmt.Println("------")
delete(m1, "wzy")
fmt.Println(m1)


打印结果:


微信图片_20221112152103.jpg


排序


map没有直接排序的内置方法


下面介绍一种排序思路:


我们取出map的key,存储到切片中,对key进行排序,再根据排序后的key取出map中的值。

实现思路如下;


package main
import (
   "fmt"
   "math/rand"
   "sort"
   "time"
)
func main() {
   // 初始化随机数种子
   rand.Seed(time.Now().UnixNano())
   // 声明+初始化map
   var scoreMap = make(map[string]int, 100)
   // 填充数据
   for i := 0; i < 100; i++ {
      key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
      value := rand.Intn(100)          //生成0~99的随机整数
      scoreMap[key] = value            //这里的赋值用= 而不是:=
   }
   //总结: =是赋值 :=是声明并赋值
   // 取出map中所有的key 存到keys切片中
   var keys = make([]string, 0, 200)
   for key := range scoreMap {
      keys = append(keys, key)
   }
   // 对切片进行排序
   sort.Strings(keys)
   // 按照排序后的keys遍历map
   for _, key := range keys {
      fmt.Println(key, scoreMap[key])
   }
}


注意


  1. 定义变量时,var 和 :=不能同时存在,因为:=代表声明并初始化,同时使用会提示重复声明错误。
  2. Go生成可变的随机数需要设置随机种子,我们一般将时间戳设置为随机种子:rand.Seed(time.Now().UnixNano())


应用实战


如何生成map类型的切片?


// 元素为map的切片
var s = make([]map[string]int, 1, 10)
fmt.Println(s)
// 先初始化map
s[0] = make(map[string]int, 1)
// 赋值
s[0]["wzyage"] = 18
fmt.Printf("s类型:%T s的值:%v\n",s,s)


打印结果:


微信图片_20221112152107.jpg


如何生成切片类型的map?


// 值为切片类型的map
var m = make(map[string][]int, 1)
m["北京"] = []int{1, 2, 3} //声明并初始化了
fmt.Printf("m类型:%T m的值:%v", m, m)


打印结果:


微信图片_20221112152110.jpg


思考题


有没有办法通过make()初始化且赋值呢?

经过一番研究之后,发现是不可以的,make()的作用就是初始化为默认值,指定容量。

比如我们改写一下上面生成切片类型map的栗子:


// 值为切片类型的map
var m = make(map[string][]int, 1)
// 用make初始化切片
m["北京"] = make([]int, 3)
fmt.Printf("m类型:%T m的值:%v", m, m)


打印结果:


微信图片_20221112152113.jpg


总结:只能通过make()函数初始化(分配内存地址),不能使用make直接赋值。


总结


这篇文章汇总了map的知识点,包括:map的声明和初始化、map的取值、map的赋值、map删除元素、map虽然不能直接排序,但是我们可以通过借助切片保存key来排序。

以及如何map和切片如何进行搭配使用。

相关文章
|
10月前
|
Linux Go iOS开发
Go语言100个实战案例-进阶与部署篇:使用Go打包生成可执行文件
本文详解Go语言打包与跨平台编译技巧,涵盖`go build`命令、多平台构建、二进制优化及资源嵌入(embed),助你将项目编译为无依赖的独立可执行文件,轻松实现高效分发与部署。
1543 162
|
10月前
|
存储 前端开发 JavaScript
Go语言实战案例-项目实战篇:编写一个轻量级在线聊天室
本文介绍如何用Go语言从零实现一个轻量级在线聊天室,基于WebSocket实现实时通信,支持多人消息广播。涵盖前后端开发、技术选型与功能扩展,助你掌握Go高并发与实时通信核心技术。
1004 158
|
11月前
|
数据采集 数据挖掘 测试技术
Go与Python爬虫实战对比:从开发效率到性能瓶颈的深度解析
本文对比了Python与Go在爬虫开发中的特点。Python凭借Scrapy等框架在开发效率和易用性上占优,适合快速开发与中小型项目;而Go凭借高并发和高性能优势,适用于大规模、长期运行的爬虫服务。文章通过代码示例和性能测试,分析了两者在并发能力、错误处理、部署维护等方面的差异,并探讨了未来融合发展的趋势。
1163 0
|
11月前
|
存储 人工智能 Go
Go-Zero全流程实战即时通讯
Go-Zero 是一个功能丰富的微服务框架,适用于开发高性能的即时通讯应用。它具备中间件、工具库和代码生成器,简化开发流程。本文介绍其环境搭建、项目初始化及即时通讯功能实现,涵盖用户认证、消息收发和实时推送,帮助开发者快速上手。
568 0
|
11月前
|
数据采集 Go API
Go语言实战案例:使用context控制协程取消
本文详解 Go 语言中 `context` 包的使用,通过实际案例演示如何利用 `context` 控制协程的生命周期,实现任务取消、超时控制及优雅退出,提升并发程序的稳定性与资源管理能力。
577 152
|
11月前
|
负载均衡 监控 Java
微服务稳定性三板斧:熔断、限流与负载均衡全面解析(附 Hystrix-Go 实战代码)
在微服务架构中,高可用与稳定性至关重要。本文详解熔断、限流与负载均衡三大关键技术,结合API网关与Hystrix-Go实战,帮助构建健壮、弹性的微服务系统。
1003 1
微服务稳定性三板斧:熔断、限流与负载均衡全面解析(附 Hystrix-Go 实战代码)
|
11月前
|
安全 Go 开发者
Go语言实战案例:使用sync.Mutex实现资源加锁
在Go语言并发编程中,数据共享可能导致竞态条件,使用 `sync.Mutex` 可以有效避免这一问题。本文详细介绍了互斥锁的基本概念、加锁原理及实战应用,通过构建并发安全的计数器演示了加锁与未加锁的区别,并封装了一个线程安全的计数器结构。同时对比了Go中常见的同步机制,帮助开发者理解何时应使用 `Mutex` 及其注意事项。掌握 `Mutex` 是实现高效、安全并发编程的重要基础。
|
11月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
11月前
|
Go 开发者
Go语言实战案例:使用select监听多个channel
本文为《Go语言100个实战案例 · 网络与并发篇》第5篇,详解Go并发核心工具`select`的使用。通过实际案例讲解如何监听多个Channel、实现多任务处理、超时控制和非阻塞通信,帮助开发者掌握Go并发编程中的多路异步事件处理技巧。
|
11月前
|
数据采集 编解码 监控
Go语言实战案例:使用channel实现生产者消费者模型
本文是「Go语言100个实战案例 · 网络与并发篇」第4篇,通过实战案例详解使用 Channel 实现生产者-消费者模型,涵盖并发控制、任务调度及Go语言并发哲学,助你掌握优雅的并发编程技巧。

热门文章

最新文章