首页 > 其他分享 >【go从入门到精通】一文把map字典搞得明明白白

【go从入门到精通】一文把map字典搞得明明白白

时间:2024-04-06 18:30:14浏览次数:28  
标签:map string fmt key go scoreMap make 字典

Map

map是一种元素对的无序集合,一组称为元素value,另一组为唯一键索引key。 未初始化map的值为nil。map 是引用类型,可以使用如下声明:

var map1 map[keytype]valuetype

([keytype] 和 valuetype 之间允许有空格,但是 Gofmt 移除了空格)

在声明的时候不需要知道 map 的长度,map 是可以动态增长的。

        map的底层存储方式为数组,在存储时key不能重复,当key重复时,value进行覆盖,我们通过key进行hash运算(可以简单理解为把key转化为一个整形数字)然后对数组的长度取余,得到key存储在数组的哪个下标位置,最后将key和value组装为一个结构体,放入数组下标处,看下图:

map定义

        key 可以是任意可以用 == 或者 != 操作符比较的类型,比如 string、int、float。所以数组、函数、字典、切片和结构体不能作为 key (含有数组切片的结构体不能作为 key,只包含内建类型的 struct 是可以作为 key 的),但是指针和接口类型可以。

        value 可以是任意类型的;通过使用空接口类型,我们可以存储任意值,但是使用这种类型作为值时需要先做一次类型断言。map 也可以用函数作为自己的值,这样就可以用来做分支结构:key 用来选择要执行的函数。

        map 传递给函数的代价很小:在 32 位机器上占 4 个字节,64 位机器上占 8 个字节,无论实际上存储了多少数据。通过 key 在 map 中寻找值是很快的,比线性查找快得多,但是仍然比从数组和切片的索引中直接读取要慢 100 倍;所以如果你很在乎性能的话还是建议用切片来解决问题。

map基本使用

map 可以用 {key1: val1, key2: val2} 的描述方法来初始化,就像数组和结构体一样。

map 是引用类型的,内存用 make 方法来分配。map 的初始化:

var map1 = make(map[keytype]valuetype)

map初始化

map 容量: 和数组不同,map 可以根据新增的 key-value 对动态的伸缩,因此它不存在固定长度或者最大限制。但是你也可以选择标明 map 的初始容量 capacity,就像这样:make(map[keytype]valuetype,cap)。

例如:

map2 := make(map[string]float32, 100)

当 map 增长到容量上限的时候,如果再增加新的 key-value 对,map 的大小会自动加 1。所以出于性能的考虑,对于大的 map 或者会快速扩张的 map,即使只是大概知道容量,也最好先标明。

在一个 nil 的slice中添加元素是没问题的,但对一个map做同样的事将会生成一个运行时的panic。

可正常运行:

package main
func main() {  
    var s []int
    s = append(s, 1)
}

会发生错误:

package main
func main() {  
    var m map[string]int
    m["one"] = 1 // 错误

}

map的key访问,val1, isPresent := map1[key1] 或者 val1 = map1[key1] 的方法获取 key1 对应的值 val1。

这里有一些定义 map 的例子:

// 声明但未初始化map,此时是map的零值状态
map1 := make(map[string]string, 5)

map2 := make(map[string]string)

// 创建了初始化了一个空的的map,这个时候没有任何元素
map3 := map[string]string{}

// map中有三个值
map4 := map[string]string{"a": "1", "b": "2", "c": "3"}

从 map1 中删除 key1,直接 delete(map1, key1) 就可以。如果 key1 不存在,该操作不会产生错误。

delete(map4, "a")

map 默认是无序的,不管是按照 key 还是按照 value 默认都不排序。如果你想为 map 排序,需要将 key(或者 value)拷贝到一个切片,再对切片排序(使用 sort 包)。

map中的数据都是成对出现的,map的基本使用示例代码如下:

func main() {
    scoreMap := make(map[string]int, 8)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    fmt.Println(scoreMap)
    fmt.Println(scoreMap["小明"])
    fmt.Printf("type of a:%T\n", scoreMap)
}   

输出:

    map[小明:100 张三:90]
    100
    type of a:map[string]int  

map也支持在声明的时候填充元素,例如:

func main() {
    userInfo := map[string]string{
        "username": "pprof.cn",
        "password": "123456",
    }
    fmt.Println(userInfo) //
}

判断某个键是否存在

Go语言中有个判断map中键是否存在的特殊写法,格式如下:

    value, ok := map[key]   

举个例子:

func main() {
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    // 如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值
    v, ok := scoreMap["张三"]
    if ok {
        fmt.Println(v)
    } else {
        fmt.Println("查无此人")
    }
}  

map的遍历

Go语言中使用for range遍历map。

func main() {
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    scoreMap["王五"] = 60
    for k, v := range scoreMap {
        fmt.Println(k, v)
    }
}  

但我们只想遍历key的时候,可以按下面的写法:

func main() {
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    scoreMap["王五"] = 60
    for k := range scoreMap {
        fmt.Println(k)
    }
}  

注意: 遍历map时的元素顺序与添加键值对的顺序无关。

删除键值对

使用delete()内建函数从map中删除一组键值对,delete()函数的格式如下:

    delete(map, key)  

其中,    map:表示要删除键值对的map    key:表示要删除的键值对的键   

示例代码如下:

func main(){
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    scoreMap["王五"] = 60
    delete(scoreMap, "小明")//将小明:100从map中删除
    for k,v := range scoreMap{
        fmt.Println(k, v)
    }
}  

按照指定顺序遍历map

 func main() {
    rand.Seed(time.Now().UnixNano()) //初始化随机数种子

    var scoreMap = make(map[string]int, 200)

    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)
    //按照排序后的key遍历map
    for _, key := range keys {
        fmt.Println(key, scoreMap[key])
    }
}

元素为map类型的切片

下面的代码演示了切片中的元素为map类型时的操作:

func main() {
    var mapSlice = make([]map[string]string, 3)
    for index, value := range mapSlice {
        fmt.Printf("index:%d value:%v\n", index, value)
    }
    fmt.Println("after init")
    // 对切片中的map元素进行初始化
    mapSlice[0] = make(map[string]string, 10)
    mapSlice[0]["name"] = "王五"
    mapSlice[0]["password"] = "123456"
    mapSlice[0]["address"] = "红旗大街"
    for index, value := range mapSlice {
        fmt.Printf("index:%d value:%v\n", index, value)
    }
} 

值为切片类型的map

下面的代码演示了map中值为切片类型的操作:

func main() {
    var sliceMap = make(map[string][]string, 3)
    fmt.Println(sliceMap)
    fmt.Println("after init")
    key := "中国"
    value, ok := sliceMap[key]
    if !ok {
        value = make([]string, 0, 2)
    }
    value = append(value, "北京", "上海")
    sliceMap[key] = value
    fmt.Println(sliceMap)
}

Map的比较运算符

        Go Map对值的类型没有限制,但是对键的类型有严格的要求,因为它必须保证键的唯一性。Go 要求键类型必须支持两个比较运算符==!=

        需要注意的一点是,在 Go 中,function/map/slices 只支持和nil比较,它们不支持自己类型的比较,如果运行以下代码,您将看到无效操作错误:

package main

import "fmt"

func main() {
    s1 := make([]int, 1)
    s2 := make([]int, 2)
    f1 := func() {}
    f2 := func() {}
    m1 := make(map[int]string)
    m2 := make(map[int]string)
    fmt.Println(s1 == s2)
    fmt.Println(f1 == f2)
    fmt.Println(m1 == m2)
}
// Output
invalid operation: s1 == s2 (slice can only be compared to nil)
invalid operation: f1 == f2 (func can only be compared to nil)
invalid operation: m1 == m2 (map can only be compared to nil)

排序

按键对map排序

对我的键进行排序相对容易,创建一个键集合并使用 golang 排序包sort.Strings进行排序。

package main

import (
	"fmt"
	"sort"
)

func main() {
	population := map[string]int{
		"Australia":  24982688,
		"Qatar":      2781677,
		"Wales":      3139000,
		"Burundi":    11175378,
		"Guinea":     12414318,
		"Niger":      22442948,
		"Brazil":     209469333,
		"Malta":      484630,
		"Peru":       31989256,
		"Yemen":      28498687,
		"Ireland":    4867309,
		"Kenya":      51393010,
		"Montserrat": 5900,
		"Cuba":       11338138,
		"Nicaragua":  6465513,
		"Jordan":     9956011,
		"Gabon":      2119275,
	}

	keys := make([]string, 0, len(population))
    for k := range population {
        keys = append(keys, k)
    }
    sort.Strings(keys)
 
    for _, k := range keys {
        fmt.Println(k, population[k])
    }

}

按值对map进行排序

按值排序稍微复杂一些。最好的方法是创建一个键和值属性的结构。

创建的结构体应该实现golang 排序接口,使其能够进行排序

package main

import (
	"fmt"
	"sort"
)

type Pair struct {
	Key   string
	Value int
}

type PairList []Pair


func (p PairList) Len() int           { return len(p) }
func (p PairList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value }

func main() {
	population := map[string]int{
		"Australia":  24982688,
		"Qatar":      2781677,
		"Wales":      3139000,
		"Burundi":    11175378,
		"Guinea":     12414318,
		"Niger":      22442948,
		"Brazil":     209469333,
		"Malta":      484630,
		"Peru":       31989256,
		"Yemen":      28498687,
		"Ireland":    4867309,
		"Kenya":      51393010,
		"Montserrat": 5900,
		"Cuba":       11338138,
		"Nicaragua":  6465513,
		"Jordan":     9956011,
		"Gabon":      2119275,
	}

	p := make(PairList, len(population))

	i := 0
	for k, v := range population {
		p[i] = Pair{k, v}
		i++
	}

	
	sort.Sort(p)
	//p is sorted
	
	for _, k := range p {
        fmt.Printf("%v\t%v\n", k.Key, k.Value)
    }


}

传参

         关于传参,我们可以看 【go从入门到精通】函数详解-CSDN博客  这篇文章,那么大家思考下map传参是值传递还是引用传递呢?

标签:map,string,fmt,key,go,scoreMap,make,字典
From: https://blog.csdn.net/pbymw8iwm/article/details/136479907

相关文章

  • django图书推荐系统 计算机专业毕业设计源码89399
    摘 要随着时代的不断更新,社会的不断变换,信息技术的飞速发展,计算机科技技术也逐步走向成熟。图书推荐系统对于当今社会来说是必不可少的一个信息组成部分,它可以管理大量图书、大量读者、让读者有条不紊的进行评分图书,大大减小了工作量,并且提高了工作效率。本文研究的图书推......
  • Rancher-rke: E0404 14:22:44.616099 5841 memcache.go:287] couldn‘t get resource
    一、根因    1、非正常关闭了主机。    2、导致docker上的metrics容器进程挂掉。二、解决办法    1、重启docker        systemctlrestartdocker    2、清理处于Exited状态的pod        dockerrm`dockerps-a|......
  • Go+云原生高级开发工程师进阶路线及资料推荐
    云原生这几年非常火,很多同学都在学习云原生相关技术,我也在如何进阶为Go+云原生高级开发工程师?中,详细介绍了如何学习,以使自己快速进阶为Go+云原生高级开发。这里我再快速总结下学习路线,并提供路线中涉及到的学习资料供你下载。学习路线本着只看优秀课程、不重复学习、学习......
  • [iAlgo Insight - 树上 K 祖先] 倍增解决
    Problem:1483.树节点的第K个祖先Tag:TreeDifficulty:HardClassic:......
  • Java基础知识总结(第八篇):集合:Collection(List、Set)、Map、Collections 工具类
    声明:        1.本文根据韩顺平老师教学视频自行整理,以便记忆       2.若有错误不当之处,请指出系列文章目录Java基础知识总结(第一篇):基础语法Java基础知识总结(第二篇):流程控制语句(分支控制和循环控制)Java基础知识总结(第三篇):数组、排......
  • 2024-04-06:用go语言,给你两个非负整数数组 rowSum 和 colSum, 其中 rowSum[i] 是二维矩
    2024-04-06:用go语言,给你两个非负整数数组rowSum和colSum,其中rowSum[i]是二维矩阵中第i行元素的和,colSum[j]是第j列元素的和,换言之你不知道矩阵里的每个元素,但是你知道每一行和每一列的和。请找到大小为rowSum.lengthxcolSum.length的任意非负整数矩阵。且该......
  • Golang中的强大Web框架Fiber详解
    Golang 取消首页编程手机软件硬件安卓苹果手游教程平面服务器首页 > 脚本专栏 > Golang >Golang Web框架FiberGolang中的强大Web框架Fiber详解2023-10-2410:31:51 作者:技术的游戏在不断发展的Web开发领域中,选择正确的框架可以极大地影响项目的效......
  • sqlmap基础知识(三)
    一、sqlmap的基本使用指定检测级别sqlmap使用的payloads直接从文本文件xml/payloads.xml中载入根据该文件顶部的相关指导说明进行设置,如果sqlmap漏过了特定的注入,你可以选择自己修改指定的payload用于检测level有5级,级别越高检测越全,默认为1-level1默认等级,执行基本......
  • 阿里云购买ECS后 部署GO
     一installnginx检测APTsudoaptinstall-ycurlgnupg2ca-certificateslsb-release安装NGINX sudoaptinstallnginxsudoufwapplist查询http sudoufwallow'NginxHTTP'查询状态sudoufwstatus 二修改nginx.conf文件server{listen80;#监......
  • Go 实战|使用 Wails 构建轻量级的桌面应用:仿微信登录界面 Demo
    概述本文探讨Wails框架的使用,从搭建环境到开发,再到最终的构建打包,本项目源码GitHub地址:https://github.com/mazeyqian/go-run-wechat-demo前言Wails是一个跨平台桌面应用开发框架,他允许开发者利用Go的性能优势,并结合任何前端技术栈,如React、Vue或Svelte,来创建桌面应......