声明map
和切片的定义一样,我们定义map未进行初始化时,map==nil。 map和切片一样,也是引用类型,不是值类型。
var m1 map[string]int //声明 fmt.Println(m1 == nil) //返回true
没有初始化,说明没有在内存中开辟空间,没有内存地址
初始化
map的初始化一定要先声明,再初始化;不能直接初始化,否则会报错:undefined
var m1 map[string]int m1 = make(map[string]int, 10) //要估算好map的容量,避免在程序运行期间在动态扩容(动态扩容会影响程序运行效率) m1["lucky"] = 18 m1["jason"] = 24 fmt.Println(m1)
打印结果:
注意:要估算好map的容量,避免在程序运行期间再动态扩容(动态扩容会影响程序运行效率)
也可以使用:=
简化,代表声明并初始化。
我们把上面的代码简化一下:
//简化 := 表示声明并初始化 m1 := make(map[string]int,10) m1["lucky"] = 18 m1["jason"] = 24 fmt.Println(m1)
打印结果:
我们发现结果是一样的。
开发过程中我们根据场景来判断使用哪种方式来进行声明、初始化操作。
取值
取值非常简单 map[key] 的方式就能取值了,例如
fmt.Println(m1["jason"]) fmt.Println(m1["jason1"]) //map查询不存在的key也不会报错 返回了空值
打印结果:
注意:map查询不存在的key不会报错的,返回了空值。
取值判断
上面提到了map查询不存在的key值也不会报错,而是返回了空值。
我们如何判断取到的值是否为空值呢?
建议大家map取值的时候这么写
value,ok := m1["jason1"] if ok { fmt.Println(value) }else { fmt.Println("不存在") }
打印结果:
遍历取值
取出键值对
for k, v := range m1 { fmt.Println(k,v) }
打印结果:
只取键
for k := range m1 { fmt.Println(k) }
打印结果:
只取值
for _, v := range m1 { fmt.Println(v) }
打印结果:
删除 delete()
map的删除很简单,内置了delete函数;
不像切片移除元素那么复杂,切片移除元素只能通过分割+append的方式。
var m1 map[string]int m1 = make(map[string]int, 10) m1["lucky"] = 18 m1["jason"] = 24 fmt.Println(m1) delete(m1,"jason") fmt.Println(m1)
打印结果:
删除不存在的key
删除不存在的key,也不会报错。
var m1 map[string]int m1 = make(map[string]int, 10) m1["lucky"] = 18 m1["jason"] = 24 fmt.Println(m1) fmt.Println("------") delete(m1, "wzy") fmt.Println(m1)
打印结果:
排序
map没有直接排序的内置方法
下面介绍一种排序思路:
我们取出map的key,存储到切片中,对key进行排序,再根据排序后的key取出map中的值。
实现思路如下;
package main import ( "fmt" "math/rand" "sort" "time" ) func main() { // 初始化随机数种子 rand.Seed(time.Now().UnixNano()) // 声明+初始化map var scoreMap = make(map[string]int, 100) // 填充数据 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) // 按照排序后的keys遍历map for _, key := range keys { fmt.Println(key, scoreMap[key]) } }
注意
- 定义变量时,var 和 :=不能同时存在,因为:=代表声明并初始化,同时使用会提示重复声明错误。
- Go生成可变的随机数需要设置
随机种子
,我们一般将时间戳设置为随机种子:rand.Seed(time.Now().UnixNano())
应用实战
如何生成map类型的切片?
// 元素为map的切片 var s = make([]map[string]int, 1, 10) fmt.Println(s) // 先初始化map s[0] = make(map[string]int, 1) // 赋值 s[0]["wzyage"] = 18 fmt.Printf("s类型:%T s的值:%v\n",s,s)
打印结果:
如何生成切片类型的map?
// 值为切片类型的map var m = make(map[string][]int, 1) m["北京"] = []int{1, 2, 3} //声明并初始化了 fmt.Printf("m类型:%T m的值:%v", m, m)
打印结果:
思考题
有没有办法通过make()初始化且赋值呢?
经过一番研究之后,发现是不可以的,make()的作用就是初始化为默认值,指定容量。
比如我们改写一下上面生成切片类型map的栗子:
// 值为切片类型的map var m = make(map[string][]int, 1) // 用make初始化切片 m["北京"] = make([]int, 3) fmt.Printf("m类型:%T m的值:%v", m, m)
打印结果:
总结:只能通过make()函数初始化(分配内存地址),不能使用make直接赋值。
总结
这篇文章汇总了map的知识点,包括:map的声明和初始化、map的取值、map的赋值、map删除元素、map虽然不能直接排序,但是我们可以通过借助切片保存key来排序。
以及如何map和切片如何进行搭配使用。