【Golang】map

*本文笔记参考:b站【尚硅谷】Golang入门到实战教程

map是key-value数据结构,又称为字段或关联数组。

1、map的声明

var 变量名 map[keytype]valuetype

key的数据类型通常为int、string类型,也可以为bool、数字、指针、channel,还可以是只包含前面几个类型的接口、数组、结构体;但是,不能为slice、map、function,因为这几个没法用==判断。

value的数据类型通常为数字(整数、浮点数)、string、map、struct

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

var a map[string]string
fmt.Println(a)
// 输出:map[]
func main() {
	var a map[string]string
	a["no1"] = "宋江"
	a["no2"] = "吴用"
	a["no1"] = "武松"
	a["no3"] = "吴用"
	fmt.Println(a)
}
// 输出:
//panic: assignment to entry in nil map
//goroutine 1 [running]:
//main.main()
//        E:/study/Go_WorkSpace/src/code/test/main.go:9 +0x32
//exit status 2
func main() {    
    var a map[string]string    
    // 使用map前,需要先make,make的作用就是给map分配数据空间    
    a = make(map[string]string, 10)    
    a["no1"] = "go"
    a["no2"] = "hello"
    fmt.Println(a)
}
//输出:map[no1:go no2:hello]

说明:

  1. map在使用前一定要make;

  2. make里如果不指定map的size,则默认size为1;

  3. map的key不能重复,如果重复了,则以最后的key-value为准;

  4. map的value是可以重复的;

  5. map的key-value是无序的。

2、map的使用

1)先声明,再make,而后赋值

func main() {
	// 声明
	var a map[string]string
	// make
	a = make(map[string]string, 2)
	// 赋值
	a["no1"] = "go"
	fmt.Println(a)
}

2)声明时直接make,而后赋值

func main() {
	// 声明时直接make
	var a = make(map[string]string, 2)
	// 赋值
	a["no1"] = "go"
	fmt.Println(a)
}

3)声明时直接赋值

func main() {
	// 声明时直接赋值
	a := map[string]string{
		"no1": "go",
		"no2": "hello",
	}
	fmt.Println(a)
}

4)实例:存放2个学生的信息,每个学生有sex和address信息

func main() {
	// 声明时直接make
	var students = make(map[string]map[string]string)
    // 直接make
	students["no1"] = make(map[string]string)
    // 赋值
	students["no1"]["sex"] = "male"
	students["no1"]["address"] = "泗泾"

	students["no2"] = make(map[string]string)
	students["no2"]["sex"] = "female"
	students["no2"]["address"] = "松江"
	fmt.Println(students)
}
func main() {
	// 声明时直接make
	var students = make(map[string]map[string]string)
    // 直接赋值
	students["no1"] = map[string]string{
		"sex":     "male",
		"address": "泗泾",
	}

	students["no2"] = map[string]string{
		"sex":     "female",
		"address": "松江",
	}
	fmt.Println(students)
}
//输出:
//map[no1:map[address:泗泾 sex:male] no2:map[address:松江 sex:female]]

3、map的增删改查

1)增加与更改

// map["key"] = value  // key存在则更改,不存在则增加
func main() {
	// 声明时直接赋值
	a := map[string]string{
		"no1": "go",
		"no2": "hello",
	}
	a["no3"] = "hahah"
	fmt.Println(a)
}
//输出:map[no1:go no2:hello no3:hahah]

2)删除

// delete(map, "key")
delete(a, "no3")

删除所有的key的方法:

  1. 没有专门的方法一次删除所有key,因此,可以遍历key,逐个删除。

    func main() {
    	// 声明时直接赋值
    	a := map[string]string{
    		"no1": "go",
    		"no2": "hello",
    	}
    	a["no3"] = "hahah"
    	fmt.Println(a)
    	
    	for i, _ := range a {  //遍历key,逐个删除
    		delete(a, i)
    	}
    	fmt.Println(a)
    }
  2. make一个新的空间,a = make(map[string]string),make一个新的,让原来的成为垃圾,被GC回收。

    func main() {
    	// 声明时直接赋值
    	a := map[string]string{
    		"no1": "go",
    		"no2": "hello",
    	}
    	a["no3"] = "hahah"
    	fmt.Println(a)
    	
    	a = map[string]string{}  //make一个新的空间
    	fmt.Println(a)
    }
    //输出:
    //map[no1:go no2:hello no3:hahah]
    //map[]

3)查找

val, findRes := a["no1"]
if findRes {
	fmt.Println("有no1这个key,值为", val)
} else {
	fmt.Println("没有no1这个key")
}

4、map的遍历

不能用for循环遍历,因为map的下标不一定是数字。使用for-range遍历:

for k, v := range a { 
	fmt.Printf("k=%v, v=%v\n", k, v)
}

map的长度:len(a)

5、map切片

map切片使map的个数动态变化(注意,是map的个数,不是一个map中key-value的个数)。

例:使用一个map记录monster的信息name和age,即一个monster对应一个map,并且monster的个数可以动态增加:

func main() {
	// 先声明,再make,再赋值
	var monster []map[string]string
	monster = make([]map[string]string, 2)
	monster[0] = make(map[string]string)
	monster[0]["name"] = "monkey"
	monster[0]["age"] = "50"
	// 声明时直接赋值
	newMonster := map[string]string{
		"name": "elephant",
		"age":  "100",
	}
    //原来monster有2个map,增加1个,现在有3个map
	monster = append(monster, newMonster) 
	fmt.Println(monster)
}
//输出:[map[age:50 name:monkey] map[] map[age:100 name:elephant]]

6、map排序

  • golang中没有专门的方法对map的key排序;

  • golang中的map默认是无序的,也不是按照添加的顺序存放,每次遍历,得到的结果可能都不同;

  • golang中map的排序,是先将key进行排序,然后根据key值遍历输出即可:将map的key放入到切片中,对切片排序,然后根据key值遍历输出。

func main() {
	// map的排序
	map1 := make(map[int]int, 10)
	map1[10] = 10
	map1[1] = 1
	map1[8] = 8
	map1[4] = 4
	map1[6] = 6
	// 将map的key放入切片中
	var keys []int
	for k, _ := range map1 {
		keys = append(keys, k)
	}
	//排序
	sort.Ints(keys)
	fmt.Println(keys)
	for _, k := range keys {
		fmt.Printf("map1[%v]=%v", k, map1[k])
	}
}
//输出
[1 4 6 8 10]
map1[1]=1 map1[4]=4 map1[6]=6 map1[8]=8 map1[10]=10 

7、map的使用细节

  1. map是引用类型,在一个函数接收map,修改后,会直接修改原来的map;

  2. map能动态增长键值对(map-key):map的容量达到上限后,再想增加map元素,会自动扩容,并不会发生panic;但是切片的动态增长需要用到append;

  3. map的value也经常使用struct类型,更适合管理复杂的数据(比双层map更好);

    package main
    
    import (
    	"fmt"
    )
    
    type Stu struct {
    	Sex     string
    	Address string
    }
    
    func main() {
    	//map的key为int类型,value为结构体
    	var students = make(map[string]Stu)
    	students["no1"] = Stu{"male", "泗泾"}
    
    	students["no2"] = Stu{"female", "松江"}
    	fmt.Println(students)
    }
    //输出
    map[no1:{male 泗泾} no2:{female 松江}]

8、课堂练习

使用map[string]map[string]string 的map类型,key表示用户名,是唯一的,不可以重复。如果某个用户存在,就将其密码修改为“888888”,如果不存在就增加这个用户信息(包括昵称nickname 和 密码pwd)。编写一个函数 modifyUser(users map[string]map[string]string)完成上述功能。

package main

import "fmt"

func modifyUser(users map[string]map[string]string, name string) {
	//判断users中是否有该用户名
	if users[name] != nil {
		users[name]["pwd"] = "888888"
	} else {
		users[name] = map[string]string{
			"nickname": name,
			"pwd":      "888888",
		}
	}
}

func main() {
	users := make(map[string]map[string]string, 10)
	users["tom"] = map[string]string{
		"pwd":      "123456",
		"nickname": "tom",
	}
	modifyUser(users, "tom")
	modifyUser(users, "mary")
	fmt.Println(users)
}
//输出
map[mary:map[nickname:mary pwd:888888] tom:map[nickname:tom pwd:888888]]

你可能感兴趣的:(Golang,golang,开发语言,后端)