go-map

map的介绍

  map是key-value数据结构,又称为字段或者关联数组。在编程中经常使用到

map的声明

基本语法

var map 变量名 map[keytype]valuetype

key可以是什么类型

golang 中的 map,的 key 可以是很多种类型,比如 bool, 数字,string, 指针, channel , 还可以是只包含前面几个类型的 接口, 结构体, 数组。通常 key 为 int 、string。
注意: slice, map 还有 function 不可以,因为这几个没法用 == 来判断
valuetype 可以是什么类型
valuetype 的类型和 key 基本一样,这里我就不再赘述了。通常为: 数字(整数,浮点数),string,map,struct
map的声明举例
var a map[string]string 
var a map[string]int 
var a map[int]string 
var a map[string]map[string]string
注意:声明是不会分配内存的,初始化需要 make ,分配内存后才能赋值和使用。
代码演示:
package main

import "fmt"

func main() {
    var a map[string]string
    // 在使用map前,需要先make,make的作用就是给map分配数据空间
    a = make(map[string]string,10)
    a["name1"]="bingle1"
    a["name2"]="bingle2"
    a["name3"]="bingle3"
    a["name4"]="bingle4"
    fmt.Println(a)
}

执行结果为:

map[name1:bingle1 name2:bingle2 name3:bingle3 name4:bingle4]

对上面代码的说明:

  1、map 在使用前一定要 make

  2、map 的 key 是不能重复,如果重复了,则以最后这个 key-value 为准

  3、map 的 value 是可以相同的.

  4、map 的 key-value 是无序、

  5、make 内置函数数目

  内建函数make分配并初始化一个类型为切片、映射、或通道的对象。其实第一个实参为类型,而非值。make的返回类型与其参数相同,而非指向它的指针,其具体结果取决于具体的类型:

  切片:size指定了其长度,该切片的容量等于其长度。切片支持第二个整数实参可用来指定不同的容量;它必须不小于其长度,因此make([]int 0, 10)会分配一个长度为0,容量为10的切片。

map的使用

方式1: 

package main

import "fmt"

func main() {
    var a map[string]string
    // 在使用map前,需要先make,make的作用就是给map分配数据空间
    a = make(map[string]string,10)
    a["name1"] = "bingle1"
    a["name2"] = "bingle2"
    a["name3"] = "bingle3"
    a["name4"] = "bingle4"
    fmt.Println(a)
}

方式 2:

package main

import "fmt"

func main() {
    names :=make(map[string]string)
    names["name1"] ="bingle1"
    names["name2"] ="bingle2"
    names["name3"] ="bingle3"
    names["name4"] ="bingle4"
    fmt.Println(names)
}

方式 3:

package main

import "fmt"

func main() {
    names := map[string]string{
        "name1": "bingle1",
        "name2": "bingle2",
        "name3": "bingle3",
        "name4": "bingle4",
    }
    names["name2"] = "bingle222222"
    fmt.Println("names = ", names)
}

map的增删改查操作

1、map的增加和更新:

  map["key"] = value //如果 key 还没有,就是增加,如果 key 存在就是修改。
2、map删除:
  delete(map,"key") ,delete 是一个内置函数,如果 key 存在,就删除该 key-value,如果 key 不存在,不操作,但是也不会报错

内建函数delete按照指定的键将元素从映射中删除,若 m 为 nil 或者 无此元素,delete不进行操作.

package main

import "fmt"

func main() {
    names := map[string]string{
        "name1": "bingle1",
        "name2": "bingle2",
        "name3": "bingle3",
        "name4": "bingle4",
    }
    delete(names,"name1")
    fmt.Println("names = ", names)
}

细节说明:

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

package main

import "fmt"

func main() {
    names := map[string]string{
        "name1": "bingle1",
        "name2": "bingle2",
        "name3": "bingle3",
        "name4": "bingle4",
    }
    names = make(map[string]string)
    fmt.Println("names = ", names)
}

3、map查找

package main

import "fmt"

func main() {
    names := map[string]string{
        "name1": "bingle1",
        "name2": "bingle2",
        "name3": "bingle3",
        "name4": "bingle4",
    }
    val1,ok1 := names["name1"]
    val2,ok2 := names["name1111"]
    if ok1 {
        fmt.Printf("有name1 key 值为 %v \n",val1)
    }else {
        fmt.Printf("没有name1 key值")
    }
    if ok2 {
        fmt.Printf("有name2 key 值为 %v \n",val2)
    }else {
        fmt.Printf("没有name2 key值")
    }
}

对上面代码说明:说明:如果 heroes 这个 map 中存在 "no1" , 那么 findRes 就会返回 true,否则返回 false

map遍历

说明:map 的遍历使用 for-range 的结构遍历
package main

import "fmt"

func main() {
    names := map[string]string{
        "name1": "bingle1",
        "name2": "bingle2",
        "name3": "bingle3",
        "name4": "bingle4",
    }
    for k, v := range names {
        fmt.Printf("k = %v ,v = %v \n", k, v)
    }
}

map的长度

 

 

内置 len 返回 v 的长度,这取决于具体类型:

  数组:v 中元素的数量

  数组指针:*v 中元素的数量(v 为 nil 的时候panic)

  切片、映射:v 中元素的数量,若 v 为 nil ,len(v) 为零

  字符串:v 中字节的数量

  通道:通道缓存中队列(未读取)元素的数量,若 v 为 nil ,len(v) 为零

package main

import "fmt"

func main() {
    names := map[string]string{
        "name1": "bingle1",
        "name2": "bingle2",
        "name3": "bingle3",
        "name4": "bingle4",
    }
    fmt.Println(len(names))
}

map切片

基本介绍:

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

案例:

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

package main
import (
    "fmt"
)

func main() {
    //1. 声明一个map切片
    var monsters []map[string]string
    monsters = make([]map[string]string, 2) //准备放入两个妖怪
    //2. 增加第一个妖怪的信息
    if monsters[0] == nil {
        monsters[0] = make(map[string]string, 2)
        monsters[0]["name"] = "牛魔王"
        monsters[0]["age"] = "500"
    }

    if monsters[1] == nil {
        monsters[1] = make(map[string]string, 2)
        monsters[1]["name"] = "玉兔精"
        monsters[1]["age"] = "400"
    }

    // 下面这个写法越界。
    // if monsters[2] == nil {
    //     monsters[2] = make(map[string]string, 2)
    //     monsters[2]["name"] = "狐狸精"
    //     monsters[2]["age"] = "300"
    // }

    //这里我们需要使用到切片的append函数,可以动态的增加monster
    //1. 先定义个monster信息
    newMonster := map[string]string{
        "name" : "新的妖怪~火云邪神",
        "age" : "200",
    }
    monsters = append(monsters, newMonster)

    fmt.Println(monsters)
}

map 排序

基本介绍:

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

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

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

代码如下:

package main

import (
    "fmt"
    "math/rand"
    "sort"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano()) //初始化随机数种子

    var scoreMap = make(map[string]int, 200)

    for i := 0; i < 100; i++ {
        key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
        value := rand.Intn(100)          //生成0~99的随机整数
        scoreMap[key] = value
    }
    //取出map中的所有key存入切片keys
    var keys = make([]string, 0, 200)
    for key := range scoreMap {
        keys = append(keys, key)
    }
    //对切片进行排序
    sort.Strings(keys)
    //按照排序后的key遍历map
    for _, key := range keys {
        fmt.Println(key, scoreMap[key])
    }
}

map 使用细节

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

package main

import (
    "fmt"
    "math/rand"
    "sort"
    "time"
)

func modify(scoreMap map[string]int) {
    scoreMap["stu01"] = 999
}

func main() {
    rand.Seed(time.Now().UnixNano()) //初始化随机数种子

    var scoreMap = make(map[string]int, 200)

    for i := 0; i < 100; i++ {
        key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
        value := rand.Intn(100)          //生成0~99的随机整数
        scoreMap[key] = value
    }
    //取出map中的所有key存入切片keys
    var keys = make([]string, 0, 200)
    for key := range scoreMap {
        keys = append(keys, key)
    }
    //对切片进行排序
    sort.Strings(keys)
    //按照排序后的key遍历map
    for _, key := range keys {
        fmt.Println(key, scoreMap[key])
    }
    fmt.Println("==============")
    modify(scoreMap)
    for _, key := range keys {
        fmt.Println(key, scoreMap[key])
    }
}

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

3、map 的 value 也经常使用 struct 类型,更适合管理复杂的数据(比前面 value 是一个 map 更好)

  比如 value 为 Student 结构体

package main

import "fmt"

// 定义一个学生结构体
type Student struct {
    Name string
    Age int
    Address string
}

func main() {
    students := make(map[string]Student,10)
    stu1 := Student{"bingel1", 18, "北京"}
    stu2 := Student{"bingel2", 28, "上海"}
    students["stu1"] = stu1
    students["stu2"] = stu2

    fmt.Println(students)
    //遍历各个学生信息
    for k, v := range students {
        fmt.Printf("学生的编号是%v \n", k)
        fmt.Printf("学生的名字是%v \n", v.Name)
        fmt.Printf("学生的年龄是%v \n", v.Age)
        fmt.Printf("学生的地址是%v \n", v.Address)
        fmt.Println()
    }
}

 

posted @ 2021-04-13 15:06  冰乐  阅读(227)  评论(0编辑  收藏  举报