• Go语言 Map教程


    什么是Map?

    Map是 Go 中的内置类型,用于存储键值对

    让我们以一家拥有几名员工的初创公司为例。为简单起见,我们假设所有这些员工的名字都是唯一的。

    我们正在寻找一种数据结构来存储每个员工的工资。Map将非常适合此用例。员工的姓名可以是键,薪水可以是值。

    如何创建Map?

    可以通过将键和值的类型传递给make函数来创建映射。以下是创建新Map的语法。

    make(map[type of key]type of value)  
    employeeSalary := make(map[string]int)  
    
    • 1
    • 2

    上面的代码行创建了一个名为employeeSalary的映射,其中包含string键和int值。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := make(map[string]int)
        fmt.Println(employeeSalary)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Run in Playground

    上面的程序创建了一个employeeSalarystring键和int值命名的映射。上面的程序将打印

    map[]  
    
    • 1

    由于我们尚未向Map添加任何元素,因此它是空的。

    将项目添加到Map

    向映射添加新项目的语法与数组的语法相同。下面的程序向employeeSalaryMap添加了一些新员工。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := make(map[string]int)
        employeeSalary["steve"] = 12000
        employeeSalary["jamie"] = 15000
        employeeSalary["mike"] = 9000
        fmt.Println("employeeSalary map contents:", employeeSalary)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Run in Playground

    我们增加了三名员工stevejamie以及mike他们相应的工资。

    上面的程序打印出,

    employeeSalary map contents: map[steve:12000 jamie:15000 mike:9000]  
    
    • 1

    也可以在声明本身期间初始化映射。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := map[string]int {
            "steve": 12000,
            "jamie": 15000,
        }
        employeeSalary["mike"] = 9000
        fmt.Println("employeeSalary map contents:", employeeSalary)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Run in Playground

    上面的程序employeeSalary在声明本身期间声明并添加了两个元素。随后又添加了一个带有键的元素mike。程序打印出

    employeeSalary map contents: map[jamie:15000 mike:9000 steve:12000]  
    
    • 1

    不一定只有字符串类型才是键。所有可比较的类型(例如布尔值、整数、浮点数、复数、字符串……)也可以是键。甚至用户定义的类型(例如结构体)也可以是键。如果您想了解更多有关可比较类型的信息,请访问http://golang.org/ref/spec#Comparison_operators

    Map的零值

    Map的零值为nil。如果您尝试向nil映射添加元素,则会发生运行时报错。因此,在添加元素之前必须初始化Map

    package main
    
    func main() {  
        var employeeSalary map[string]int
        employeeSalary["steve"] = 12000
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Run in Playground

    在上面的程序中,我们employeeSalary正在nil尝试向Map添加一个新的键。程序会报错

    panic: assignment to entry in nil map
    
    • 1

    从映射中检索键的值

    现在我们已经向Map添加了一些元素,让我们学习如何检索它们。map[key]是检索映射元素的语法。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := map[string]int{
            "steve": 12000,
            "jamie": 15000,
            "mike": 9000,
        }
        employee := "jamie"
        salary := employeeSalary[employee]
        fmt.Println("Salary of", employee, "is", salary)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Run in Playground

    上面的程序非常简单。jamie检索并打印员工的工资。程序打印出

    Salary of jamie is 15000  
    
    • 1

    如果某个元素不存在会发生什么?映射将返回该元素类型的零值。在映射的情况下employeeSalary,如果我们尝试访问不存在的元素,则将返回int其零值。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := map[string]int{
            "steve": 12000,
            "jamie": 15000,
        }
        fmt.Println("Salary of joe is", employeeSalary["joe"])
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Run in Playground

    上述程序的输出是

    Salary of joe is 0  
    
    • 1

    上面的程序返回 joe 的工资为0。当我们尝试检索映射中不存在的键的值时,不会出现运行时错误。

    检查key是否存在

    在上一节中我们了解到,当键不存在时,将返回该类型的零值。当我们想要查明键是否确实存在于映射中时,这没有帮助。

    例如,我们想知道Map中是否存在某个键employeeSalary

    value, ok := map[key]  
    
    • 1

    上面是查找映射中是否存在特定键的语法。如果ok为 true,则键存在且其值存在于变量 中value,否则键不存在。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := map[string]int{
            "steve": 12000,
            "jamie": 15000,
        }
        newEmp := "joe"
        value, ok := employeeSalary[newEmp]
        if ok == true {
            fmt.Println("Salary of", newEmp, "is", value)
            return
        }
        fmt.Println(newEmp, "not found")
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Run in Playground

    在上面的程序中,第 1 行。由于不存在,ok因此将为假。joe因此程序将打印,

    joe not found  
    
    • 1

    迭代Map中的所有元素

    range循环的形式用于for迭代映射的所有元素。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := map[string]int{
            "steve": 12000,
            "jamie": 15000,
            "mike":  9000,
        }
        fmt.Println("Contents of the map")
        for key, value := range employeeSalary {
            fmt.Printf("employeeSalary[%s] = %d\n", key, value)
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Run in Playground

    上述程序输出,

    Contents of the map  
    employeeSalary[mike] = 9000  
    employeeSalary[steve] = 12000  
    employeeSalary[jamie] = 15000  
    
    • 1
    • 2
    • 3
    • 4

    一个重要的事实是,在使用时从映射中检索值的顺序for range不能保证对于程序的每次执行都是相同的。它也与元素添加到Map的顺序不同

    从Map中删除项目

    *delete(map, key)*是keymap. 删除函数不返回任何值。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := map[string]int{
            "steve": 12000,
            "jamie": 15000,     
            "mike": 9000,
        }
        fmt.Println("map before deletion", employeeSalary)
        delete(employeeSalary, "steve")
        fmt.Println("map after deletion", employeeSalary)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Run in Playground

    上面的程序删除了key为steve并打印

    map before deletion map[steve:12000 jamie:15000 mike:9000]  
    map after deletion map[mike:9000 jamie:15000]  
    
    • 1
    • 2

    如果我们尝试删除映射中不存在的键,则不会出现运行时错误。

    Map值存放结构体

    到目前为止,我们仅将员工的工资存储在Map中。如果我们也能够在Map中存储每个员工的国家/地区不是很好吗?这可以通过使用结构体来实现。员工可以表示为包含字段工资和国家/地区的结构,它们将使用字符串键和结构值存储在映射中。让我们编写一个程序来了解如何做到这一点。

    package main
    
    import (  
        "fmt"
    )
    
    type employee struct {  
        salary  int
        country string
    }
    
    func main() {  
        emp1 := employee{
            salary:  12000,
            country: "USA",
        }
        emp2 := employee{
            salary:  14000,
            country: "Canada",
        }
        emp3 := employee{
            salary:  13000,
            country: "India",
        }
        employeeInfo := map[string]employee{
            "Steve": emp1,
            "Jamie": emp2,
            "Mike":  emp3,
        }
    
        for name, info := range employeeInfo {
            fmt.Printf("Employee: %s Salary:$%d  Country: %s\n", name, info.salary, info.country)
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    Run in Playground

    在上面的程序中,employeestruct 包含字段salarycountry。我们创建了三名员工emp1emp2并且emp3

    我们用我们创建的三个员工初始化一个具有键类型string和值类型的映射。该程序将打印

    Employee: Mike Salary:$13000  Country: India  
    Employee: Steve Salary:$12000  Country: USA  
    Employee: Jamie Salary:$14000  Country: Canada  
    
    • 1
    • 2
    • 3

    Map长度

    可以使用len函数确定映射的长度。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := map[string]int{
            "steve": 12000,
            "jamie": 15000,
        }
        fmt.Println("length is", len(employeeSalary))
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Run in Playground

    *上面程序中的len(employeeSalary)*返回映射的长度。上面的程序打印出,

    length is 2  
    
    • 1

    Map是引用类型

    切片类似,映射是引用类型。当映射分配给新变量时,它们都指向相同的内部数据结构。因此,其中一个进行更改将反映在另外一个地方。

    package main
    
    import (  
        "fmt"
    )
    
    func main() {  
        employeeSalary := map[string]int{
            "steve": 12000,
            "jamie": 15000,     
            "mike": 9000,
        }
        fmt.Println("Original employee salary", employeeSalary)
        modified := employeeSalary
        modified["mike"] = 18000
        fmt.Println("Employee salary changed", employeeSalary)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Run in Playground

    在行号中。上述程序的 14 号employeeSalary被分配给modified. 在下一行中,Map中的工资mike更改为。迈克的工资现在也到了。程序输出,18000``modified``18000``employeeSalary

    Original employee salary map[jamie:15000 mike:9000 steve:12000]  
    Employee salary changed map[jamie:15000 mike:18000 steve:12000]  
    
    • 1
    • 2

    当映射作为参数传递给函数时,情况也是如此。当对函数内部的映射进行任何更改时,调用者也可以看到它。

    Map比较

    不能用==运算符来比较Map。只能==用于检查Map是否为nil

    package main
    
    func main() {  
        map1 := map[string]int{
            "one": 1,
            "two": 2,
        }
    
        map2 := map1
    
        if map1 == map2 {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Run in Playground

    上面的程序将无法编译并出现错误

    invalid operation: map1 == map2 (map can only be compared to nil)  
    
    • 1

    检查两个映射是否相等的一种方法是逐一比较每个映射的各个元素。另一种方法是使用反射

    本教程到此结束。希望你喜欢它。请留下您的评论。

  • 相关阅读:
    消息队列 RocketMQ 消息重复消费问题(原因及解决)
    WPF之MVVM模式
    C++模板详解
    Java设计模式-结构型模式-适配器模式
    小程序源码:社群微群人脉系统-多玩法安装简单
    (附源码)计算机毕业设计SSM基于框架的动漫设计
    广州华锐互动:办税服务厅税务登记VR仿真体验让税务办理更加灵活高效
    月薪12K,蝶变向新,勇往直前—她通过转行测试实现月薪翻倍~
    包管理器pacman常用方法
    【EI会议征稿】第七届电子器件与机械工程国际学术会议(ICEDME 2024)
  • 原文地址:https://blog.csdn.net/qq497811258/article/details/133880114