28、Go 复合数据类型 - map 映射

作者: 温新

分类: 【Go基础】

阅读: 595

时间: 2023-08-29 16:07:09

hi,我是温新

map 简介

**map(映射)是一种数据结构,用于存储一系列无序的键值对,映射基于键来存储值。**把它当前 PHP 中的关联数组来就看就容易理解了。

map 是一种集合,可以像遍历数组或切片那样来遍历它。由于 map 是由 Hash 表实现的,因此对 map 的读取顺序是不固定的。

关于 map 需要注意的是:

1、map 是无序的,每次打印的 map 都会不一样,map 必须通过 key 获取值;

2、map 的长度是不固定的,和切片可以扩展;

3、同一个 map 中的 key 必须唯一;

4、map 的值可以是任何数据类型。

map 创建

可以使用 var 关键字来定义 map,也可以使用内置函数 make。

使用 var 关键字定义 map

// 格式
var variableName map[keyType]valueType

使用 var 关键字声明 map时,未初始化的 map 的默认值是 nil。nil map 不能存放键值对。若要使用 map 存储键值对,则必须在声明时初始化,或使用 make 函数分配到内存空间。案例如下:

package main

import "fmt"

func main() {
    // 声明一个 map
    var myMap map[int]int
    fmt.Println(myMap) // []

    // map 赋值
    myMap = map[int]int{1: 100, 2: 200}
    fmt.Println(myMap)
}

使用 make 函数

// 格式
变量名 := make(map[keyType]valueType)

使用 make 函数或使用映射字面量创建 map 是最常见的方式,案例如下:

package main

import "fmt"

func main() {
    // 创建一个映射,键是 string 类型,值是 int 类型
    myMap := make(map[string]int)

    // 赋值
    myMap["lucy"] = 3
    myMap["jack"] = 4
    fmt.Println(myMap)
}

map 初始化赋值

package main

import "fmt"

func main() {
    // 字面量初始化并赋值
    colors := map[string]string{
        "red":    "#da1337",
        "orange": "#e956a22",
    }
    fmt.Println(colors)
}

map 的使用

元素赋值

package main

import "fmt"

func main() {
    colors := map[string]string{}
    // 元素赋值
    colors["red"] = "#da1337"
    fmt.Println(colors)
}

下面是报错的案例。通过声明一个未初始化的 map 可以创建一个值为 nil,但不能用于存储键值对,否则报错,案例如下:

package main

import "fmt"

func main() {
    // 声明映射,不赋值,将得到一个 nil
    var colors map[string]string
    fmt.Println(colors)

    // 赋值
    colors["red"] = "#da1337"
}

运行代码时,将会报错,信息如下:

panic: assignment to entry in nil map

查找与遍历

从 Map 取值有两种方式,一种是获得值以及一个表示这个键是否存在的标志;另一种是只返回对应的值,再判断这个值是否为零值,以此来确保键存在。

package main

import "fmt"

func main() {
    names := map[string]int{
        "lucy": 100,
        "jack": 90,
    }

    value, exists := names["lucy"]
    if exists {
        fmt.Println(value)
    }

    // 不存在的 key
    v, e := names["foo"]
    fmt.Println(v, e) // 返回值 0 false
}

通过 key 可以获取 map 中对应的 value 值。当 key 不存在时,会得到该 value 值类型的默认值,如 int 将得到 0,string 将得到空,而程序不会报错。因此可以通过value, exists := map[key]获取 value 是否存在。

下面是遍历 map 的案例

package main

import "fmt"

func main() {
    person := map[string]string{
        "name":   "王美丽",
        "age":    "19",
        "gender": "",
    }

    for key, value := range person {
        if value != "" {
            fmt.Printf("Key: %s Value:%s]\n", key, value)
        }
    }
}

删除元素

内置函数 delete(map, key) 用于删除 map 的某个元素。删除函数不返回任何值。

package main

import "fmt"

func main() {
    person := map[string]string{
        "name":   "王美丽",
        "age":    "19",
        "gender": "",
    }

    delete(person, "gender")
    delete(person, "nickname")
    fmt.Println(person)
}

删除一个不存在的 key 时,不会发生任何影响,也就是什么事都没有。但是当传入的 map 变量的值是 nil 时,将导致程序抛出 panic 异常。

将 map 传递给函数

在函数间传递 map 并不会制造出该 map 的一个副本。实际上,当传递映射给一个函数,并对这个映射做修改时,所有对这个映射的引用都会受到影响。

package main

import "fmt"

func main() {
    person := map[string]string{
        "name": "王美丽",
        "age":  "19",
    }

    // 遍历 map
    for key, value := range person {
        fmt.Printf("Key: %s Value:%s]\n", key, value)
    }

    // 删除指定的 key
    removeAttr(person, "age")
    for key, value := range person {
        fmt.Printf("Key: %s Value:%s]\n", key, value)
    }
}

// 删除一个属性
func removeAttr(person map[string]string, key string) {
    delete(person, key)
}

map 是引用类型

map 是一个引用类型,将一个 map 赋值给一个新变量时,它们指向同一块内存。因此无论修改哪一个变量的内容都会影响另外一个。

package main

import "fmt"

func main() {
    person := map[string]string{
        "name": "王美丽",
        "age":  "19",
    }
    fmt.Println("原始数据", person)

    p1 := person
    p1["age"] = "20"
    fmt.Println("p1 变量", p1)
    fmt.Println("person 受到 p1 的影响", person)
}

输出结果

原始数据 map[age:19 name:王美丽]
p1 变量 map[age:20 name:王美丽]
person 受到 p1 的影响 map[age:20 name:王美丽]
请登录后再评论