go语言使用-引用数据类型——Map

一、概述

1、基本介绍
map是key-value数据结构,又称为字段或者关联数组。类似其它编程语言的集合,
在编程中是经常使用到。

2、map和数组的区别
map相对数组而言,可以存储信

二、基本语法

var map变量名 map[keytype]valuetype

1、 key 可以是什么类型

golang中的map,的 key 可以是很多种类型,比如 bool, 数字,string, 指针, channel , 还可以是只包含前面几个类型的 接口, 结构体, 数组
通常为int 、string
注意: slice, map 还有 function 不可以,因为这几个没法用 == 来判断

2、 valuetype 可以是什么类型

valuetype的类型和key基本一样,这里我就不再赘述了
通常为: 数字(整数,浮点数),string,map,struct

3、 注意和说明几点

  • 在给map类型赋值,必须先make空间,才能使用。
  • make 时,size , 如果程序员明确知道 key-val 有多少对,最好写明确,如果不确定的话,也可以省略,交给系统维护
  • map是无序的,既不会安装key来排序,也不会安装添加的顺序.->如何排序
  • map的key,即不能重复,如果你重复了,则相当于覆盖

4、示例代码

package main
import (
    "fmt"
)

func main() {

    var map1 map[string]map[string]string
    //在map1中保存2个学生信息[编号唯一, (名字,爱好,年龄)]

    //1. 先给map1 make空间
    map1 = make(map[string]map[string]string, 3)
    //2. 给map1["no1"] make空间
    map1["no1"] = make(map[string]string, 3)
    map1["no1"]["name"] = "小明"
    map1["no1"]["hobby"] = "看世界杯"
    map1["no1"]["age"] = "20"

    //3. 给map1["no2"] make空间
    map1["no2"] = make(map[string]string)
    map1["no2"]["name"] = "小李~" 
    map1["no2"]["hobby"] = "看欧洲杯"
    map1["no2"]["age"] = "30"

    //3. 给map1["no2"] make空间
    map1["no2"] = make(map[string]string)
    map1["no2"]["name"] = "小张" 
    map1["no2"]["hobby"] = "看欧洲杯~"
    map1["no2"]["age"] = "40"

    fmt.Println("map1=",map1)

}

三、快速入门案例

package main
import (
    "fmt"
)

func main() {

    //几个map的小案例
    //map1 map[int]string
    //1. map1 就是这个map类型的名字
    //2. map 是一个关键字表示是一个map,固定的
    //3. [int] 表示这个map的key的数据类型
    //4. string 表示这个map的value的数据类型
    var map1 map[int]string

    //在使用map之前,需要先make一个数据空间
    // make(map[int]string, 10)
    //1. make是个函数,表示给map1分配数据空间
    //2. map[int]string 分配的空间类型
    //3. 10 表示分配空间大小
    map1 = make(map[int]string, 10)

    map1[10] = "tom"
    map1[11] = "tom"
    fmt.Println(map1)
//key还可以是 接口,结构体,数组
    var arr1 = [3]int{1,2,3}
    var arr2 = [3]int{1,2,4}
    fmt.Println("arr1=arr2?", arr1==arr2)

    var map2 map[[3]int]string 
    map2 = make(map[[3]int]string , 10)
    map2[arr1] = "jack"
    map2[arr2] = "scott"

    fmt.Println("map2", map2)

}

四、map使用的方式:

1、先声明再make

var m map[string]string
m = make(map[string]string,10)

2、声明的同时make

var m = make(map[string]string,10)

3、声明并直接赋值

var m  map[string]string  map[string]string{"id":"01"}

五、map的增删改查操作

1、map增加和更新:

map["key"] = value //如果key还没有,就是增加,如果key存在就是修改。

var heros = map[string]string{
        "no1" : "宋江",
        "no2" : "小卢",
        "no3" : "吴用",
    } // 底层隐藏 make

    heros["no4"] = "公孙胜" //新增
    heros["no1"] = "武松" //覆盖


    fmt.Println("herso", heros)


    //删除map的一个key-val

    delete(heros, "no2")
    fmt.Println("herso", heros)

    //清空map
    //heros = make(map[string]string)
    fmt.Println("herso", heros)

2、map删除:

1)delete(map,"key") ,delete是一个内置函数,如果key存在,就删除该key-value,如果key不存在,不操作,但是也不会报错
go语言使用-引用数据类型——Map_第1张图片
2)细节说明

  • 如果我们要删除map的所有key ,没有一个专门的方法一次删除,可以遍历一下key, 逐个删除
  • 或者 map = make(…),make一个新的,让原来的成为垃圾,被gc回收【推荐】

代码示例:

//删除map的一个key-val

    delete(heros, "no2")
    fmt.Println("herso", heros)

    //清空map
    //heros = make(map[string]string)
    fmt.Println("herso", heros)

3、map查找

//从map中,查找对应的key-val

    //如果有 res = true
    //如果没有 res = false
    val, res := heros["no1"]
    if res {
        fmt.Printf("有no1 对应的值=%v\n", val)
    } else {
        fmt.Printf("没有\n")
    }

4、map增删改查完整代码:

package main
import (
    "fmt"
)

func main() {

    var heros = map[string]string{
        "no1" : "宋江",
        "no2" : "小卢",
        "no3" : "吴用",
    } // 底层隐藏 make

    heros["no4"] = "公孙胜" //新增
    heros["no1"] = "武松" //覆盖


    fmt.Println("herso", heros)


    //删除map的一个key-val

    delete(heros, "no2")
    fmt.Println("herso", heros)

    //清空map
    //heros = make(map[string]string)
    fmt.Println("herso", heros)

    //从map中,查找对应的key-val

    //如果有 res = true
    //如果没有 res = false
    val, res := heros["no1"]
    if res {
        fmt.Printf("有no1 对应的值=%v\n", val)
    } else {
        fmt.Printf("没有\n")
    }

}

六、Map遍历

map的遍历使用for-range的结构遍历

package main
import (
    "fmt"
)

func main() {

    var map1 map[string]map[string]string
    //在map1中保存2个学生信息[编号唯一, (名字,爱好,年龄)]

    //1. 先给map1 make空间
    map1 = make(map[string]map[string]string, 3)
    //2. 给map1["no1"] make空间
    map1["no1"] = make(map[string]string, 3)
    map1["no1"]["name"] = "小明"
    map1["no1"]["hobby"] = "看世界杯"
    map1["no1"]["age"] = "20"

    //3. 给map1["no2"] make空间
    map1["no2"] = make(map[string]string)
    map1["no2"]["name"] = "小李~" 
    map1["no2"]["hobby"] = "看欧洲杯"
    map1["no2"]["age"] = "30"

    //3. 给map1["no2"] make空间
    map1["no3"] = make(map[string]string)
    map1["no3"]["name"] = "梅西" 
    map1["no3"]["hobby"] = "踢足球"
    map1["no3"]["age"] = "32"


    //fmt.Println("map1=",map1)

    //遍历 for -- range

    for key1, val1 := range map1 {
        fmt.Printf("编号为%v\n", key1)
        //对val1 (map) 再次遍历
        for key2, val2 := range val1 {
            fmt.Printf("\t%v=%v\n", key2, val2)
        }
        fmt.Println()
    }
}

七、map切片

1、基本介绍

切片的数据类型如果是map,则我们称为 slice of map,map切片,这样使用则map个数就可以动态变化了。

2、案列
要求:使用一个map来记录monster的信息 name 和 age, 也就是说一个monster对应一个map,并且妖怪的个数可以动态的增加=>map切片

package main
import (
    "fmt"
)

func main() {

    //演示map使用
    //  要求:使用一个map来记录monster
    // 的信息 name 和 age, 也就是说一个
    // monster对应一个map,并且妖怪的个
    // 数可以动态的增加=>map切片

    //1. 声明一个map切片
    var monsters []map[string]string

    //2. 我们先给 切片 分配空间
    monsters = make([]map[string]string, 3)

    //3. 给第一个妖怪的map分配空间
    if monsters[0] == nil {
        monsters[0] = make(map[string]string, 2) // monster 记录什么
        monsters[0]["name"] = "红孩儿"
        monsters[0]["age"] = "10"
    }

    //3. 给第2个妖怪的map分配空间
    if monsters[1] == nil {
        monsters[1] = make(map[string]string, 2) // monster 记录什么
        monsters[1]["name"] = "牛魔王"
        monsters[1]["age"] = "500"
    }


    //3. 给第2个妖怪的map分配空间
    if monsters[2] == nil {
        //monsters[2] = make(map[string]string, 2) // monster 记录什么
        monsters[2]["name"] = "白骨精"
        monsters[2]["age"] = "400"
    }

    fmt.Println("monsters=", monsters)

}

八、map排序

1、基本介绍

  • golang中没有一个专门的方法针对map的key进行排序

  • golang中的map默认是无序的,注意也不是按照添加的顺序存放的,你每次遍历,得到的输出可能不一样.

  • golang中map的排序,是先将key进行排序,然后根据key值遍历输出即可

2、案例演示

  • map中的key 是int类型的案例
package main
import (
    "fmt"
)

func test(m map[string]string) {
    m["no1"] = "tomjack"
}

//先定义一个结构体(struct Stu)

type Stu struct {
    Name string
    Age int
    IsMarrid bool
}

func main() {
    var heros2 = map[string]string{
        "no1" : "宋江",
        "no2" : "小卢",
        "no3" : "吴用",
        "no4" : "豹子头",
        "no5" : "武松",
        "no6" : "鲁智深",
    }
    heros2["no7"] = "顺平"  //只要有一次make, 后面添加key-val就会自动增长

    fmt.Println("heros2=", heros2)
    test(heros2)
    fmt.Println("heros2=", heros2)



    // map的value 也经常使用struct 类型,
    // 更适合管理复杂的数据(比前面value是一个map更好),
    // 比如value为 Student结构体 
    // 【案例演示,因为还没有学结构体,体验一下即可】

    //需求:使用map保存2个学生 【学号[唯一], 学生信息[名字,年龄(int), 婚否(bool)]】

    //1. 先定义一个结构体(struct Stu)

    //2. 创建map
    // 
    var stusMap map[string]Stu 
    //3. 给stusMap make空间
    stusMap = make(map[string]Stu, 2)
    //4. 给stusMap放入学生
    stu1 := Stu{"贾宝玉", 18, false}
    stu2 := Stu{"林黛玉", 16, false}
    stusMap["no001"] = stu1
    stusMap["no002"] = stu2

    fmt.Println("stusMap=",stusMap)


}
  • map的key是string, 我们希望按照string的码值的大小排序
package main
import (
    "fmt"
    "sort"
)

//封装一个冒泡
func bubbleSort(keysSlice []string) {
    var temp string
    //对冒泡做一个优化, 思路如果在内层循环中,一次交换交换都没有发生过,则说明
    //该数组已经是一个有序数列,就不需要再比较.
    var flag = false //

    //将for 做成双层循环

    for j := 0; j < len(keysSlice) - 1; j++ {

        for i := 0; i < len(keysSlice) - 1 - j; i++ {


            //如果前面的数比后面的数大,就交换
            if keysSlice[i] < keysSlice[i + 1] {
                flag = true
                temp = keysSlice[i]
                keysSlice[i] = keysSlice[i + 1]
                keysSlice[i + 1] = temp 
            }
        }

        if flag == true { //交换过
            flag = false 
        } else {
            // 一次都没有交换过
            break
        }
    }
}


func main() {



    var heros = map[int]string{
        1 : "宋江",
        2 : "小卢",
        3 : "吴用",
        4 : "豹子头",
        5 : "关胜",
        6 : "秦明",
        7 : "武松",
    } // 底层隐藏 make


    //遍历
    for key, val := range heros {
        fmt.Printf("key=%v val=%v\n", key, val)
    }

    //现在我们有这样一个需求,按照key的string排序.
    //如果我们的map的key是整数,那么比较简单. sort.Ints()
    //1. 先将heros的所有key放入到一个切片中 []int
    var keysSlice []int 
    for key, _ := range heros {
        keysSlice = append(keysSlice, key)  
    }
    //2. 使用系统提供方法sort.Ints()排序

    sort.Ints(keysSlice) //切片是引用类型
    fmt.Println("keysSlice=", keysSlice)
    fmt.Println()
    for _, val := range keysSlice {
        fmt.Printf("key=%v val=%v\n", val, heros[val])
    }

    //3. 我如果希望从大到小显示==》
    //4. 

    fmt.Println("---------------------------------")
    fmt.Println("---------------------------------")
    fmt.Println("---------------------------------")
    fmt.Println("---------------------------------")
    //map
    var heros2 = map[string]string{
        "no1" : "宋江",
        "no2" : "小卢",
        "no3" : "吴用",
        "no4" : "豹子头",
        "no5" : "武松",
        "no6" : "鲁智深",
    } // 底层隐藏 make
    //按照 key 的字符串大小排, 从小到大...
    // heros2==> map 的 key==> keySlice2 ==排序【从小到大】==> 遍历keySlice2,显示数据.

    var keysSlice2 []string 
    for key, _ := range heros2 {
        keysSlice2 = append(keysSlice2, key)    
    }

    //keySlice2 ==排序【从小到大】冒泡
    bubbleSort(keysSlice2) 

    //遍历keySlice2,显示数据
    for _, val := range keysSlice2 {
        fmt.Printf("key=%v val=%v\n", val, heros2[val])
    }


    //补充一个知识点, 字符串本身是可以比较大小 ??

    //fmt.Println("no3>no2=", "no3" > "no2")

}

九、map使用细节和注意事

1、map是引用类型,遵守引用类型传递的机制,在一个函数接收map,修改后,会直接修改原来的map

2、 map的容量达到后,再想map增加元素,会自动扩容,并不会发生panic,也就是说map 能动态的增长 键值对(key-value) 【案例演示】

var heros2 = map[string]string{
        "no1" : "宋江",
        "no2" : "小卢",
        "no3" : "吴用",
        "no4" : "豹子头",
        "no5" : "武松",
        "no6" : "鲁智深",
    }
    heros2["no7"] = "顺平"  //只要有一次make, 后面添加key-val就会自动增长

    fmt.Println("heros2=", heros2)
    test(heros2)
    fmt.Println("heros2=", heros2)

3、map的value 也经常使用struct 类型,更适合管理复杂的数据(比前面value是一个map更好),比如value为 Student结构体 【案例演示】

var onlineUsers map[int]*bean.User = make(map[int]*bean.User)

4、如何计算Map的长度

使用go内置函数len,源码如下:
go语言使用-引用数据类型——Map_第2张图片

你可能感兴趣的:(GO/GOWeb)