GO语言中的Map使用方法详解

 更新时间:2023年08月08日 11:32:48   作者:金戈鐡馬  
这篇文章主要给大家介绍了关于GO语言中Map使用方法的相关资料,在go语言中map是散列表的引用,map的类型是map[k]v,也就是常说的k-v键值对,需要的朋友可以参考下

Map简述

Go语言中的map(映射、字典)是一种内置的数据结构,它是一个无序的key-value对的集合,比如以身份证号作为唯一键来标识一个人的信息。Go语言中并没有提供一个set类型,但是map中的key也是不相同的,可以用map实现类似set的功能。

map格式为:

 map[keyType]valueType

在一个map里所有的键都是唯一的,而且必须是支持==和!=操作符的类型,切片、函数以及包含切片的结构类型这些类型由于具有引用语义,不能作为映射的键,使用这些类型会造成编译错误:

 dict := map[ []string ]int{} //err, invalid map key type []string

map值可以是任意类型,没有限制。map里所有键的数据类型必须是相同的,值也必须如此,但键和值的数据类型可以不相同。

注意:map是无序的,我们无法决定它的返回顺序,所以,每次打印结果的顺利有可能不同。

创建及初始化Map

创建Map

 fmt.Println(m1 == nil) 	//true
    //m1[1] = "Luffy" 		//nil的map不能使用err, panic: assignment to entry in nil map
    
    m2 := map[int]string{}	//m2, m3的创建方法是等价的
    m3 := make(map[int]string)
    fmt.Println(m2, m3) 		//map[] map[]

    m4 := make(map[int]string, 10) 	//第2个参数指定容量
    fmt.Println(m4)                	//map[]

创建m4的方法指定了map的初始创建容量。 与slice类似,后期在使用过程中,map可以自动扩容。只不过map更方便一些,不用借助类似append的函数,直接赋值即可。如,m1[17] = "Nami"。赋值过程中,key如果与已有map中key重复,会将原有map中key对应的value覆盖。

但是!对于map而言,可以使用len()函数,但不能使用cap()函数

初始化Map

也可以直接指定初值,要保证key不重复。

    //1、定义同时初始化
    var m1 map[int]string = map[int]string{1: "Luffy", 2: "Sanji"}
    fmt.Println(m1) //map[1:Luffy 2:Sanji]

    //2、自动推导类型 :=
    m2 := map[int]string{1: "Luffy", 2: "Sanji"}
    fmt.Println(m2)

常用操作

赋值

    m1 := map[int]string{1: "Luffy", 2: "Sanji"}
    m1[1] = "Nami"   //修改
    m1[3] = "Zoro"  //追加, go底层会自动为map分配空间
    fmt.Println(m1) //map[1:Nami 2:Sanji 3:Zoro]

    m2 := make(map[int]string, 10) 	//创建map
    m2[0] = "aaa"
    m2[1] = "bbb"
    fmt.Println(m2)           		//map[0:aaa 1:bbb]
    fmt.Println(m2[0], m2[1]) 		//aaa bbb

遍历

Map的迭代顺序是不确定的,并且不同的哈希函数实现可能导致不同的遍历顺序。在实践中,遍历的顺序是随机的,每一次遍历的顺序都不相同。这是故意的,每次都使用随机的遍历顺序可以强制要求程序不会依赖具体的哈希函数实现。

     m1 := map[int]string{1: "Luffy", 2: "Sanji"}
    //遍历1,第一个返回值是key,第二个返回值是value
    for k, v := range m1 {
        fmt.Printf("%d ----> %s\n", k, v)
        //1 ----> Luffy
        //2 ----> yoyo
    }

    //遍历2,第一个返回值是key,第二个返回值是value(可省略)
    for k := range m1 {
        fmt.Printf("%d ----> %s\n", k, m1[k])
        //1 ----> Luffy
        //2 ----> Sanji
    }

有时候可能需要知道对应的元素是否真的是在map之中。可以使用下标语法判断某个key是否存在。map的下标语法将产生两个值,其中第二个是一个布尔值,用于报告元素是否真的存在。

如果key存在,第一个返回值返回value的值。第二个返回值为 true。

    value, ok := m1[1]
    fmt.Println("value = ", value, ", ok = ", ok) //value =  mike , ok =  true

如果key不存在,第一个返回值为空,第二个返回值为false。

value2, has := m1[3]
fmt.Println("value2 = ", value2, ", has = ", has) //value2 =   , has =  false

删除

使用delete()函数,指定key值可以方便的删除map中的k-v映射。

    m1 := map[int]string{1: "Luffy", 2: "Sanji", 3: "Zoro"}
    
    for k, v := range m1 {	//遍历,第一个返回值是key,第二个返回值是value
        fmt.Printf("%d ----> %s\n", k, v)
    }
    //1 ----> Sanji
    //2 ----> Sanji
    //3 ----> Zoro
    delete(m1, 2) 		//删除key值为2的map

    for k, v := range m1 {
        fmt.Printf("%d ----> %s\n", k, v)
    }
    //1 ----> Luffy
    //3 ----> Zoro

delete()操作是安全的,即使元素不在map中也没有关系;如果查找删除失败将返回value类型对应的零值。如:

    delete(m1, 5) 		//删除key值为5的map

    for k, v := range m1 {
        fmt.Printf("%d ----> %s\n", k, v)
    }
    //1 ----> Luffy
    //3 ----> Zoro

Map输出结果依然是原来的样子,且不会有任何错误提示。

Map做函数参数

与slice 相似,在函数间传递映射并不会制造出该映射的一个副本,不是值传递,而是引用传递

func DeleteMap(m map[int]string, key int) {
    delete(m, key) //删除key值为2的map
    for k, v := range m {
        fmt.Printf("len(m)=%d, %d ----> %s\n", len(m), k, v)
}
    //len(m)=2, 1 ----> Luffy
    //len(m)=2, 3 ----> Zoro
}

func main() {
    m := map[int]string{1: "Luffy", 2: "Sanji", 3: "Zoro"}
    DeleteMap(m, 2) 	//删除key值为2的map

    for k, v := range m {
        fmt.Printf("len(m)=%d, %d ----> %s\n", len(m), k, v)
}
    //len(m)=2, 1 ----> Luffy
    //len(m)=2, 3 ----> Zoro
}

Map做函数返回值

返回的依然是引用

func test() map[int]string {
	// m1 := map[int]string{1: "Luffy", 2: "Sanji", 3: "Zoro"}
   m1 := make(map[int]string, 1)     // 创建一个初创容量为1的map
   m1[1] = "Luffy"
   m1[2] = "Sanji"                   // 自动扩容
   m1[67] = "Zoro"
   m1[2] = "Nami"                	// 覆盖 key值为2 的map
   fmt.Println("m1 = ", m1)
   return m1
}

func main() {
   m2 := test()                  	// 返回值 —— 传引用
   fmt.Println("m2 = ", m2)
}

输出:

m1 =  map[1:Luffy 2:Nami 67:Zoro]
m2 =  map[2:Nami 67:Zoro 1:Luffy]

附:判断两个map中是否有相同的key和value

通过下标访问map中的元素总会有返回值。如果k在map中,就返回对应的v。**如果不在就返回v类型的零值。**所以通过下标访问元素时,需要辨别是否真的不存在还是这个v是0。

v, ok := ages["jack"]
if !ok {
    ......
}
// 这两句话可以合并
v, ok := ages["jack"]; !ok {......}

通过下标访问map元素会有两个返回值,第二个返回值是一个布尔类型,来报告元素是否存在,一般用ok表示。

// 判断两个map是否有相同的k和v
func equal(x, y map[string]int) bool {
   if len(x) != len(y) {
      return false
   }
   for k, xv := range x {
      /**
      用!ok 来区分元素不存在,元素存在但是值为0的情况,如果只使用 xv != y[k] 在下面这个情况就是出错
      equals(map[string]int{"A":0}, map[string]int{"B":0})
      因为如果查找的k在map中不存在,会返回v类型的零值,当在第二个map中查找是否有A时,会返回0,如果只依靠返回值来比较是无法判断A是不存在还是A对应的v 就是 0
      */
      if yv, ok := y[k]; !ok || yv != xv {
         return false
      }
   }
   return true
}

总结

到此这篇关于GO语言中的Map使用方法详解的文章就介绍到这了,更多相关GO语言Map使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang双链表的实现代码示例

    golang双链表的实现代码示例

    这篇文章主要介绍了golang双链表的实现代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Go中匿名结构体的使用技巧

    Go中匿名结构体的使用技巧

    这篇文章主要给大家分享一个使用匿名结构体,提升Go编程效率的小技巧,没什么技术深度,属于在日常写代码过程中积累下来的一个提升自己编程效率的小经验
    2023-08-08
  • golang修改结构体中的切片值方法

    golang修改结构体中的切片值方法

    这篇文章主要介绍了golang修改结构体中的切片值方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Golang读写二进制文件方法总结

    Golang读写二进制文件方法总结

    使用 Golang 的 encoding/gob 包读写二进制文件非常方便,而且代码量也非常少,本文就来通过两个示例带大家了解一下encoding/gob的具体用法吧
    2023-05-05
  • golang的基础语法和常用开发工具详解

    golang的基础语法和常用开发工具详解

    这篇文章主要介绍了golang的基础语法和常用开发工具,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Mac上Go环境和VS Code的正确安装与配置方法

    Mac上Go环境和VS Code的正确安装与配置方法

    Go语言是一个新兴的语言。下面介绍一下如何在Mac系统下安装和使用这个语言,Go语言提供了mac下安装包,可直接下载安装包点击安装
    2018-03-03
  • golang操作elasticsearch的实现

    golang操作elasticsearch的实现

    这篇文章主要介绍了golang操作elasticsearch,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • GO语言字符串常用操作小结

    GO语言字符串常用操作小结

    本文主要介绍了GO语言字符串常用操作小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 详解Golang如何实现节假日不打扰用户

    详解Golang如何实现节假日不打扰用户

    这篇文章主要为大家介绍了Golang如何实现节假日不打扰用户过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • go语言context包功能及操作使用详解

    go语言context包功能及操作使用详解

    这篇文章主要为大家介绍了go语言context包功能及操作使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04

最新评论