zoukankan      html  css  js  c++  java
  • GoLang基础数据类型--->字典(map)详解

     

                       GoLang基础数据类型--->字典(map)详解

                                                作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

       可能大家刚刚接触Golang的小伙伴都会跟我一样,这个map是干嘛的,是函数吗?学过python的小伙伴可能会想到map这个函数。其实它就是Golang中的字典。下面跟我一起看看它的特性吧。map 也就是 Python 中字典的概念,它的格式为“map[keyType]valueType”。 map 的读取和设置也类似 slice 一样,通过 key 来操作,只是 slice 的index 只能是`int`类型,而 map 多了很多类型,可以是 int ,可以是 string及所有完全定义了 == 与 != 操作的类型。

    一.map的赋值方式

    1.先的声明再初始化最后赋值

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import (
    "fmt"
    "reflect"
    )

    func main() {
    var yinzhengjie map[string]string //先声明一个字典(map)名字叫做yinzhengjie。其key所对应的数据类型是“string”[字符串],value所对应的数据类型也是“string”。
    fmt.Printf("判断yinzhengjie字典是否为空:【%v】 ",yinzhengjie == nil) //声明的字典,默认为空,需要用make进行初始化操作(map是引用类型,未初始化的是指向nil,初始化了以后应该就有自己的内存空间了,所以不是nil。)所以返回值为空。
    fmt.Printf("第一次查看yinzhengjie字典的值:【%v】 ",yinzhengjie)
    yinzhengjie = make(map[string]string) //再使用make函数进行初始化创建一个非nil的map,nil map不能赋值,如果直接赋值会报错:“panic: assignment to entry in nil map”
    fmt.Printf("再次判断yinzhengjie字典是否为空:【%v】 ",yinzhengjie == nil) //你就把它理解为一个指针,没初始化就是nil,make之后分配内存了,一旦分配了内存地址就不为空了
    fmt.Printf("第二次查看yinzhengjie字典的值:【%v】 ",yinzhengjie)
    yinzhengjie["name"] = "尹正杰"
    fmt.Printf("yinzhengjie字典的类型为:【%v】 ",reflect.TypeOf(yinzhengjie))
    fmt.Printf("第三次查看yinzhengjie字典的值:【%v】 ",yinzhengjie)
    }

    #以上代码执行结果如下:
    判断yinzhengjie字典是否为空:【true】
    第一次查看yinzhengjie字典的值:【map[]】
    再次判断yinzhengjie字典是否为空:【false】
    第二次查看yinzhengjie字典的值:【map[]】
    yinzhengjie字典的类型为:【map[string]string】
    第三次查看yinzhengjie字典的值:【map[name:尹正杰]】

    复制代码

    2.直接make进行初始化之后再赋值

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    yinzhengjie := make(map[string]int) //表示创建一个key为string,value的值为int的数据类型。
    yinzhengjie["yzj"] = 25
    fmt.Println(yinzhengjie)
    }

    #以上代码执行结果如下:
    map[yzj:25]

    复制代码

    3.直接初始化赋值

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    yinzhengjie := map[string]int{
    "尹正杰":18,
    "饼干":20,
    }
    fmt.Println(yinzhengjie)
    }

    #以上代码执行结果如下:
    map[尹正杰:18 饼干:20]

    复制代码

    二.map的增删改查

    1.字典的赋值操作

    复制代码
    
    

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    yinzhengjie := make(map[int]string)
    letter := []string{"a","b","c","d","e","f","g","h"}
    for k,v := range letter{
    yinzhengjie[k] = v
    }
    fmt.Println(yinzhengjie) //注意,字典是无序的哟!
    }


    #以上代码执行结果如下:
    map[7:h 0:a 1:b 2:c 3:d 4:e 5:f 6:g]

    复制代码

    2.字典的删除操作

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    yinzhengjie := make(map[int]string)
    letter := []string{"a","b","c","d","e","f","g","h"}
    for k,v := range letter{
    //fmt.Println(k,v)
    yinzhengjie[k] = v
    }
    fmt.Println(yinzhengjie) //注意,字典是无序的哟!

    for i:=0;i<4 ;i++ {
    delete(yinzhengjie,i) //删除字典中key所对应的value.1
    }
    fmt.Println(yinzhengjie)

    for k := range yinzhengjie{
    delete(yinzhengjie,k) //删除整个字典的数据
    }
    fmt.Println(yinzhengjie)
    fmt.Println(yinzhengjie==nil) //字典的“壳子”还在,空字典也是有地址的。所以返回值是false!
    }

    #以上代码执行结果如下:
    删除之前的样子:【map[5:f 6:g 7:h 0:a 1:b 2:c 3:d 4:e]】
    第一次删除之后的样子:【map[5:f 6:g 7:h 4:e]】
    第二次删除之后的样子:【map[]】
    字典被清空之后是否为空:【false】

    复制代码

     3.字典的修改操作

    复制代码
    
    
    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    yinzhengjie := make(map[int]string)
    letter := []string{"a","b","c","d","e","f","g","h"}
    for k,v := range letter{
    //fmt.Println(k,v)
    yinzhengjie[k] = v
    }
    fmt.Printf("修改之前的样子:【%v】 ",yinzhengjie)
    yzj := yinzhengjie //map是一种引用类型,如果两个map同时指向一个底层,那么一个改变,另一个也相应的改变。
    yzj[0] = "尹正杰" //修改字典下标所对应的值。
    yzj[1] = "yinzhengjie"
    fmt.Printf("修改之后的样子:【%v】 ",yinzhengjie)//注意,字典是无序的哟!
    }

    #以上代码执行结果如下:
    修改之前的样子:【map[0:a 1:b 2:c 3:d 4:e 5:f 6:g 7:h]】
    修改之后的样子:【map[7:h 0:尹正杰 1:yinzhengjie 2:c 3:d 4:e 5:f 6:g]】

    4.字典的查询方式

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    yinzhengjie := make(map[int]string)
    letter := []string{"a","b","c","d","e","f","g","h"}
    for k,v := range letter{
    yinzhengjie[k] = v
    }
    fmt.Println(yinzhengjie) //注意,字典是无序的哟!我下面之所以通过循环遍历,是因为的确存在哪些key哟!

    for i,j := range yinzhengjie{ //遍历key和value。
    fmt.Println("key=",i,"value=",j)
    }

    for i := range yinzhengjie{ //只遍历key
    fmt.Println(i)
    }
    }


    #以上代码执行结果如下:
    map[3:d 4:e 5:f 6:g 7:h 0:a 1:b 2:c]
    key= 6 value= g
    key= 7 value= h
    key= 0 value= a
    key= 1 value= b
    key= 2 value= c
    key= 3 value= d
    key= 4 value= e
    key= 5 value= f
    3
    4
    5
    6
    7
    0
    1
    2

    复制代码

     5.原地修改字典的Value

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    type Student struct {
    ID int
    NAME string
    }

    func main() {
    dict := make(map[int]*Student)
    dict[1] = &Student{
    ID:100,
    NAME:"yinzhengjie",
    }

    dict[2] = &Student{
    ID:200,
    NAME:"尹正杰",
    }


    fmt.Println(dict[1])
    s := dict[1]
    s.ID = 100000 //原地修改字典的value.
    fmt.Println(dict)
    fmt.Println(dict[1])
    }

    #以上代码执行结果如下:
    &{100 yinzhengjie}
    map[1:0xc042044400 2:0xc042044420]
    &{100000 yinzhengjie}

    复制代码

    三.map的常用技巧

    1.判断map键值是否存在

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    yinzhengjie := make(map[int]string)
    letter := []string{"a","b","c","d","e","f","g","h"}
    for k,v := range letter{
    yinzhengjie[k] = v
    }
    fmt.Printf("字典中的值为:【%v】 ",yinzhengjie) //注意,字典是无序的哟!
    if v, ok := yinzhengjie[1]; ok {
    fmt.Println("存在key=",v)
    }else {
    fmt.Println("没有找到key=",v)
    }

    v ,ok := yinzhengjie[1]
    if ok {
    fmt.Println("再一次确认,已经存在key=",v)
    }else {
    fmt.Println("再一次确认,没有找到key=",v)
    }
    }


    #以上代码执行结果如下:
    字典中的值为:【map[3:d 4:e 5:f 6:g 7:h 0:a 1:b 2:c]】
    存在key= b
    再一次确认,已经存在key= b

    复制代码

    2.map的排序

      我们都知道字典的默认都是无需的,但是我们可以借用标准库的包来进行基于字母或数字的顺序来排序,从而达到我们想要的结果,我们就以2016全球计算机语言排行前十的案例来展示吧:

    复制代码
    
    

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import (
    "fmt"
    "sort"
    )

    func main() {
    var ProgramingLanguage = map[string]int{
    "Java": 0,
    "C": 1,
    "C++": 2,
    "Python": 3,
    "C#": 4,
    "PHP": 5,
    "JavaScript": 6,
    "Visual Basic.NET": 7,
    "Perl": 8,
    "Assembly language": 9,
    "Ruby": 10,
    }
    var SortString []string
    for k := range ProgramingLanguage {
    SortString = append(SortString, k)
    }
    sort.Strings(SortString) //会根据字母的顺序进行排序。
    for _, k := range SortString {
    fmt.Println("Key:", k, "Value:", ProgramingLanguage[k])
    }
    }

    #以上代码执行结果如下:
    Key: Assembly language Value: 9
    Key: C Value: 1
    Key: C# Value: 4
    Key: C++ Value: 2
    Key: Java Value: 0
    Key: JavaScript Value: 6
    Key: PHP Value: 5
    Key: Perl Value: 8
    Key: Python Value: 3
    Key: Ruby Value: 10
    Key: Visual Basic.NET Value: 7

    复制代码

    3.map的嵌套

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    type EmployeeInformation map[string]int

    func main() {

    StaffQuarters := make(map[string]EmployeeInformation)
    EmployeeNumber := make(EmployeeInformation)
    EmployeeNumber["yinzhengjie"] = 23
    EmployeeNumber["bingan"] = 24

    StaffQuarters["888"] = EmployeeNumber
    StaffQuarters["999"] = EmployeeInformation{"fanbinxin": 25, "zhouzhiruo": 26,}
    fmt.Println(StaffQuarters)
    }

    #以上代码执行结果如下:
    map[888:map[bingan:24 yinzhengjie:23] 999:map[fanbinxin:25 zhouzhiruo:26]]

    复制代码

    4.map的嵌套用法展示

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    Province:=make(map[string]map[string][]string) //定义省的字典
    City:=make(map[string][]string) //定义市区的字典
    Scenery := make(map[string][]string) //定义景区的字典
    Scenery["西安"] = []string{ "秦始皇兵马俑","大雁塔","大唐芙蓉园","华清池","黄巢堡国家森林公园","西安碑林博物馆","骊山国家森林公园","西安城墙","秦始皇陵","翠华山",}
    Scenery["安康"] = []string{"中坝大峡谷","香溪洞","安康双龙生态旅游度假区","瀛湖生态旅游景区","简车湾休闲景区","南宫山","天书峡景区","汉江燕翔洞景区","飞渡峡-黄安坝景区","千层河",}
    City["西安市区"]=[]string{"新城区","碑林区","莲湖区","灞桥区","未央区","雁塔区","阎良区","临潼区","长安区","高陵区","咸阳区"}
    City["安康市区"]=[]string{"汉滨区","汉阴县","石泉县","宁陕县","紫阳县","岚皋县","平利县","镇平县","旬阳县","白河县",}
    Province["陕西"]=City
    City["西安景区"] = Scenery["西安"]
    City["安康景区"] = Scenery["安康"]
    for k,v := range Province{
    fmt.Println(k,v)
    for x,y := range v{
    fmt.Println(x,y)
    }
    }
    }


    #以上代码执行结果如下:
    陕西 map[安康市区:[汉滨区 汉阴县 石泉县 宁陕县 紫阳县 岚皋县 平利县 镇平县 旬阳县 白河县] 西安景区:[秦始皇兵马俑 大雁塔 大唐芙蓉园 华清池 黄巢堡国家森林公园 西安碑林博物馆 骊山国家森林公园 西安城墙 秦始皇陵 翠华山] 安康景区:[中坝大峡谷 香溪洞 安康双龙生态旅游度假区 瀛湖生态旅游景区 简车湾休闲景区 南宫山 天书峡景区 汉江燕翔洞景区 飞渡峡-黄安坝景区 千层河] 西安市区:[新城区 碑林区 莲湖区 灞桥区 未央区 雁塔区 阎良区 临潼区 长安区 高陵区 咸阳区]]
    西安景区 [秦始皇兵马俑 大雁塔 大唐芙蓉园 华清池 黄巢堡国家森林公园 西安碑林博物馆 骊山国家森林公园 西安城墙 秦始皇陵 翠华山]
    安康景区 [中坝大峡谷 香溪洞 安康双龙生态旅游度假区 瀛湖生态旅游景区 简车湾休闲景区 南宫山 天书峡景区 汉江燕翔洞景区 飞渡峡-黄安坝景区 千层河]
    西安市区 [新城区 碑林区 莲湖区 灞桥区 未央区 雁塔区 阎良区 临潼区 长安区 高陵区 咸阳区]
    安康市区 [汉滨区 汉阴县 石泉县 宁陕县 紫阳县 岚皋县 平利县 镇平县 旬阳县 白河县]

    复制代码

    四.map的进阶知识

    1.map的挖坑

      Captial["北京"]["大兴区"]会发现这个值已经没有了,取而代之的是Captial["北京"]["密云县"]这是因为 Area 和 County 都是 map[string]int 类型的数据,Golang 直接把 ["大兴区"] 里的数据从 Area 替换成了 County,而不会递归地添加 map 中缺失的数据。

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    Captial := make(map[string]map[string]int)
    Area := make(map[string]int)
    Area["大兴区"] = 100
    Captial["北京"] = Area
    County := make(map[string]int)
    County["密云县"] = 200
    fmt.Println(Captial["北京"]["大兴区"]) //目前是可以访问到“Captial["北京"]["大兴区"]”的值的
    Captial["北京"] = County
    fmt.Println(Captial["北京"]["大兴区"]) //但是你执行了上一行的代码,你会发现你访问不到它的值100啦,但是你却发现可以访问下面一行代码的值。
    fmt.Println(Captial["北京"]["密云县"])
    }


    #以上代码执行结果如下:
    100
    0
    200

    
    
    复制代码

    2.map的填坑

      你自己想到上面的解决方法了没?其实很简单,我们只要做一个条件判断即可,代码如下:

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    Captial := make(map[string]map[string]int)
    Area := make(map[string]int)
    Area["大兴区"] = 100
    Captial["北京"] = Area

    if _, ok := Captial["北京"]; ok {
    Captial["北京"]["密云县"] = 200 //判断,如果存在Captial["北京"]这个key就只做字典的追加操作。
    }else {
    County := make(map[string]int)
    Captial["北京"] = County
    County["密云县"] = 200 //如果不存在就
    }
    fmt.Println(Captial["北京"]["大兴区"]) //可以访问到“Captial["北京"]["大兴区"]”的值100啦。
    fmt.Println(Captial["北京"]["密云县"])
    }

    #以上代码执行结果如下:
    100
    200

    复制代码

    3.定义一个集合的思想

      了解过Python的童鞋,可能听说过集合,但是我要告诉你一个好消息和一个坏消息,你想先听哪一个?坏消息就是Golang没有集合这个概念;好消息是我们可以用Golang的make函数来实现集合的思想,下面跟我一起看个例子吧!

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import "fmt"

    func main() {
    set := make(map[string]bool) //定义一个map
    set["yinzhengjie"] = true //给已经存在的变量定义为真
    if set["yinzhengjie"] {
    fmt.Printf("已经存在明为yinzhengjie的key,其值为【%v】 ",set["yinzhengjie"])

    } else {
    fmt.Println("该变量不存在!")
    }

    if set["yzj"] { //判断是否 存在变量
    fmt.Println("已经存在该变量")

    } else {
    fmt.Printf("不存在名为“yzj”的key,其值为【%v】 ",set["yzj"])

    }
    fmt.Println(set) //我们来一起查看一下这个网站吧。
    }


    #以上代码执行结果如下:
    已经存在该变量key,其值为【true】
    不存在名为“yzj”的key,其值为【false】
    map[yinzhengjie:true]

    复制代码

    4.map的寻址

       golang中的map并没有保证它们的value值的地址是不可变的,因为value值的地址很有可能被重新分配。在golang中,一个容量不断增长的map可能会导致原来map中的一些元素发生rehashing,使得他们被重新分配到新的storage location上,这样可能会导致原先得到的address变得不可用。就是所谓的map member 的 not addresable。

      换句话说,在golang设计的时候,map中的value值应该是地址不可达的,就是说直接取map中的元素的地址会报错.一个修改的办法就是把value值设置成为指针的形式,这样就相当于添加了一个额外的记录(entry),即使真正需要的那个值的位置发生了变化,也可以重定向(redirection)过去。

    复制代码

    /*
    #!/usr/bin/env gorun
    @author :yinzhengjie
    Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
    EMAIL:y1053419035@qq.com
    */

    package main

    import (
    "fmt"
    )

    type NameType struct { //定义一个结构体,类似Python语言中定义一个类的概念。
    Blog string
    }

    func main() {
    BlogAddress := make(map[string]*NameType)
    BlogAddress["yinzhengjie"] = &NameType{} //这里赋值的是指针。
    BlogAddress["yinzhengjie"].Blog = "http://www.cnblogs.com/yinzhengjie"
    fmt.Println(BlogAddress)
    }


    #以上代码执行结果如下:
    map[yinzhengjie:0xc042008230]

    复制代码

    5.扩展小知识:make和new的区别

       make 只能为 slice、map或 channel 类型分配内存并初始化,同时返回一个有初始值的 slice、map 或 channel 类型引用,不是指针。内建函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针。

    
    
    
    当你的才华还撑不起你的野心的时候,你就应该静下心来学习。当你的能力还驾驭不了你的目标的时候,你就应该沉下心来历练。问问自己,想要怎样的人生。 欢迎加入高级自动化运维之路:598432640
     
     
  • 相关阅读:
    LeetCode Single Number
    Leetcode Populating Next Right Pointers in Each Node
    LeetCode Permutations
    Leetcode Sum Root to Leaf Numbers
    LeetCode Candy
    LeetCode Sort List
    LeetCode Remove Duplicates from Sorted List II
    LeetCode Remove Duplicates from Sorted List
    spring MVC HandlerInterceptorAdapter
    yum
  • 原文地址:https://www.cnblogs.com/williamjie/p/9933335.html
Copyright © 2011-2022 走看看