Go语言--语法基础6--基本数据类型--map类型

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

1、定义声明 Map

可以使用内建函数 make 也可以使用 map 关键字来定义 Map:

复制代码
/* 声明变量,默认 map 是 nil */
var map_variable map[keyType] valueType 

示例

复制代码
var a map[int]int

key 和 value 的类型说明

  • key 可以是什么类型 :golang 中的 map 的 key 可以是很多种类型,比如 bool、数字、string、指针、channel,还可以是只包含前面几个类型的接口、结构体、数组。
    注意:slice、map 还有 function 不可以,因为这几个没法用 == 来判断。
  • value 可以是什么类型:value 的类型和 key 基本一样,通常为:数字(整数、浮点数)、string、map、struct。

map 声明举例

复制代码
var a map[string]string
var b map[string]int
var c map[int]string
var d map[string] map[string]string

注意 :声明是不会分配内存的,初始化需要 make,分配内存后才能赋值和使用。

复制代码
/* 使用 make 函数初始化 map */
map_variable = make(map[key] value)

如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对。

实例

下面实例演示了创建和读取 map:

复制代码
package main
import "fmt"
func main() {
    // 声明 map
    var countryCapitalMap map[string]string
    /* 创建集合 在使用 map 前,首先要 make 分配数据空间。*/
    countryCapitalMap = make(map[string]string)
    
    /* map 插入 key-value 对,各个国家对应的首都 */
    // 使用 map
    countryCapitalMap["France"] = "Paris"
    countryCapitalMap["Italy"] = "Rome"
    countryCapitalMap["Japan"] = "Tokyo"
    countryCapitalMap["India"] = "New Delhi"
    
    /* 使用 key 输出 map 值 */
    for country := range countryCapitalMap {
        fmt.Println("Capital of", country, "is", countryCapitalMap[country])
    }
}

以上实例运行结果为:

复制代码
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of India is New Delhi

另外一种 map 声明方式

复制代码
heroes := map[string]string{
    "no1": "chengdu", // 注意不能少了","号
    "no2": "beijing",
    "no3": "wuhan",
}
fmt.Println(heroes)
fmt.Println(heroes["no2"])

value 为 map 的案例

比如:我们要存放 3 个学生信息,每个学生有 name 和 sex 信息(思路:map[string] map[string]string):

复制代码
stuMap := make(map[string] map[string]string)
stuMap["stu01"] = make(map[string]string)
stuMap["stu01"]["name"] = "zhangsan"
stuMap["stu01"]["age"] = "10岁"
stuMap["stu01"]["addr"] = "xi'an"
stuMap["stu02"] = make(map[string]string)
stuMap["stu02"]["name"] = "lisi"
stuMap["stu02"]["age"] = "9岁"
stuMap["stu02"]["addr"] = "chognqing"
fmt.Println(stuMap)
fmt.Println(stuMap["stu01"])

2、常规操作

1. map 增加和更新

复制代码
map["key"] = value // 如果 key 还没有,就是增加;如果 key 存在就是修改

示例

复制代码
cities := make(map[string]string)
cities["no1"] = "上海"
cities["no2"] = "西安"
cities["no3"] = "天津"
fmt.Println(cities)
// 因为 no3 这个 key 值已经存在,所以下面的就是修改,若无就是增加
cities["no3"] = "天津..."
fmt.Println(cities)

2. map 删除

delete(map, "key") 是用于删除 map 元素的内置函数。如果 key 存在,就删除该 key-value;如果 key 不存在,不操作,也不会报错。

实例

复制代码
package main
import "fmt"
func main() { 
    /* 创建 map */
    countryCapitalMap := map[string] string{
        "France":"Paris",
        "Italy":"Rome",
        "Japan":"Tokyo",
        "India":"New Delhi",
    }
    fmt.Println("原始 map") 
    /* 打印 map */
    for country := range countryCapitalMap {
        fmt.Println("Capital of", country, "is", countryCapitalMap[country])
    }
    /* 删除元素 */
    delete(countryCapitalMap, "France");
    fmt.Println("Entry for France is deleted") 
    fmt.Println("删除元素后 map") 
    /* 打印 map */
    for country := range countryCapitalMap {
        fmt.Println("Capital of", country, "is", countryCapitalMap[country])
    }
}

以上实例运行结果为

复制代码
原始 map
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of India is New Delhi
Entry for France is deleted
删除元素后 map
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of India is New Delhi

注意:如果要全部删除,有两种方式:

  • 遍历所有 key,逐一删除。

  • 直接 make 一个新空间

    cities := make(map[string]string)
    fmt.Println(cities)

3. map 查找

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

复制代码
v, ok := map["key"]

如果 key 存在,oktruev 为对应的值;不存在,okfalsev 为值类型的零值。

示例

复制代码
func main() {
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    // 演示 map 查找
    v, ok := scoreMap["张三"]
    if ok {
        fmt.Println(v)
    } else {
        fmt.Println("查无此人")
    }
}

4. 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 或 value
复制代码
func main() {
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 90
    scoreMap["小明"] = 100
    scoreMap["王五"] = 60
    // 只输出键
    for k := range scoreMap {
        fmt.Println(k)
    }
    // 只输出值
    for _, v := range scoreMap {
        fmt.Println(v)
    }
}

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

复杂 map 遍历
复制代码
for k1, v1 := range stuMap {
    fmt.Println("k1 =", k1)
    for k2, v2 := range v1 {
        fmt.Printf("\t k2 =%v v2=%v \n", k2, v2)
    }
    fmt.Println()
}
按照指定顺序遍历 map
复制代码
import (
    "fmt" 
    "math/rand"
    "sort"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano()) // 初始化随机数种子
    
    var scoreMap = make(map[string]int, 200) // 定义并声明一个容量为200个 string-int 的 map
    
    for i := 0; i < 100; i++ { // i 从 0 - 99
        key := fmt.Sprintf("stu%02d", i) // 生成 stu 开头的字符串 
        // %d 数字 %2d 两位数字 %02d 不够两位做 0 填充
        // stu00 stu01 stu02 ... stu99
        value := rand.Intn(100) // 生成 0~99 的随机整数,rand 随机数生成函数
        
        scoreMap[key] = value // stu00 = 0~99 之间的随机数赋值
    }
    
    // 取出 map 中的所有 key 存入切片 keys
    var keys = make([]string, 0, 200) // 定义并生成一个 200 个容量的切片,切片名称是 keys
    
    for key := range scoreMap {
        keys = append(keys, key)
    }
    
    // 对切片进行排序
    sort.Strings(keys)
    
    // 按照排序后的 key 遍历 map
    for _, key := range keys {
        fmt.Println(key, scoreMap[key])
    }
}

课堂练习

  1. 定义一个 id 和姓名的 map 来存储学生信息,并可以遍历输出。
  2. 定义一个姓名和班级的 map 类存储学生的成绩信息,并可以完成基本的增删改查。