Hash
表是一种巧妙而且实用的数据结构,是一个无序的key/value
对的集合,其中全部的key
都是不一样的,经过给定的key
能够在常数时间复杂度内检索、更新或删除对应的value。Map
实际上是一个Hash表的引用,可以基于键快速检索出数据,键就像索引同样指向与该键关联的值。之后有机会再给你们讲Map
底层的东西,教会你们如何使用Map
才是这一节的重点,记住一点:Map
存储的是无序的键值对集合。golang
make
函数make
能够建立切片,也能够用来建立Map
。规则是这样的:数组
m := make(map[keyType]valueType) 复制代码
咱们来试着建立:markdown
month := make(map[string]int) month["January"] = 1 month["February"] = 2 month["March"] = 3 复制代码
第一行代码,建立了key
类型为string
,value
类型为int
的空Map
month
,接着,给month
赋值了三个键值对。数据结构
上面的代码,能够采用字面量的方式实现:函数
month := map[string]int{"January":1,"February":2,"March":3} // 还能够写成这样 month := map[string]int{ "January":1, "February":2, "March":3, } 复制代码
使用字面量也能够建立空Map
,大括号里面不赋值就能够了:oop
month := map[string]int{} fmt.Println(month) // 输出:map[] 复制代码
有空Map
,是否是有nil
Map
?固然是有为nil
的Map
:学习
var month map[string]int fmt.Println(month == nil) // 输出:true 复制代码
对于nil
的map
是不能存取键值对的,不然就会报错panic: assignment to entry in nil map
。可使用提到的make
函数,为其初始化:spa
var month map[string]int month = make(map[string]int) month["January"] = 1 fmt.Println(month) // 输出:map[January:1] 复制代码
天然能想到,Map
的零值就是nil
,Map
就是底层Hash
表的引用。 Map
的key
能够是内置类型,也能够是结构类型,只要可使用 ==
运算符作比较,均可以做为key
。切片、函数以及包含切片的结构类型,这些类型因为具备引用语义,不能做为key
,使用这些类型会形成编译错误:.net
month := map[[]string]int{} // 编译错误:invalid map key type []string 复制代码
对于Map
的value
来讲,就没有类型限制,固然也没有任何理由阻止用户使用切片做为Map
的值:code
m := map[string][]int{} slice := []int{1,2,3} m["slice"] = slice fmt.Println(m["slice"]) // 或者 slice := []int{1,2,3} m := map[string][]int{"slice":slice} fmt.Println(m["slice"]) 复制代码
第一段代码,建立了key
类型为string
,值为slice
类型的空Map
,接着将切片slice
赋值给了名为slice
的key
。第二段代码是第一段代码的简写版本。
Map
Map
的使用就很简单了,相似于数组,数组是使用索引,Map
使用key
获取或修改value
。
m := map[string]int{} m["January"] = 1 // 赋值 fmt.Println(m) // 输出:map[January:1] m["January"] = 10 //修改 fmt.Println(m) // 输出:map[January:10] january := m["January"] // 获取value fmt.Println(january) // 输出:10 复制代码
执行修改操做的时候,若是key
已经存在,则新值会覆盖旧值,上面代码已经体现出来了,因此key
是不容许重复的。 获取一个不存在的key
的value
的时候,会返回值类型对应的零值,这个时候,咱们就不知道是存在一个值为零值的键值对仍是键值对就根本不存在。好在,Map
给咱们提供了方法:
february,exists := m["February"] fmt.Println(february,exists) // 输出:0 false 复制代码
获取值的时候多了一个返回值,第一个返回值是value
,第二个返回值是boolean
类型变量,表示value
是否存在。这给咱们判断一个key
是否存在就提供了很大便利。
delete
--删除键值对不像Slice
,Go
为咱们提供了删除键值对的功能--delete
函数。 函数原型:
func delete(m map[Type]Type1, key Type) 复制代码
第一个参数是Map
,第二个参数是key
。
m := map[string]int{ "January":1, "February":2, "March":3, } fmt.Println(m) // 输出:map[March:3 January:1 February:2] delete(m,"January") fmt.Println(m) // 输出:map[February:2 March:3] 复制代码
删除一个不存在的键值对时,delete
函数不会报错,没任何做用。
Map
Map
无法使用for
循环遍历,跟数组、切片同样,可使用range
遍历。
for key, value := range m { fmt.Println(key, "=>", value) } 复制代码
输出:
February => 2 March => 3 January => 1 复制代码
可使用空白操做符_
忽略返回的key
或value
。屡次执行代码的时候,你会发现,返回值的顺序有多是不同的,也就是说Map
的遍历是无序的。
len
函数可使用len
函数返回Map中键值对的数量:
fmt.Println("len(m) =",len(m)) 复制代码
Map
是一种引用类型Map
是对底层数据的引用。编写代码的过程当中,会涉及到Map
拷贝、函数间传递Map
等。跟Slice
相似,Map
指向的底层数据是不会发生copy
的。
m := map[string]int{ "January":1, "February":2, "March":3, } month := m delete(month,"February") fmt.Println(m) fmt.Println(month) 复制代码
输出:
map[January:1 March:3] map[January:1 March:3] 复制代码
上面的代码,将Map
m
赋值给month
,删除了month
中的一个键值对,m
也发生了改变,说明Map
拷贝时,m
和month
是共享底层数据的,改变其中一方数据,另外一方也会随之改变。相似,在函数间传递Map
时,其实传递的是Map
的引用,不会涉及底层数据的拷贝,若是在被调用函数中修改了Map
,在调用函数中也会感知到Map
的变化。 那若是我真想拷贝一个Map
怎么办?
month := map[string]int{} m := map[string]int{ "January":1, "February":2, "March":3, } for key,value := range m{ month[key] = value } delete(month,"February") fmt.Println(m) fmt.Println(month) 复制代码
输出:
map[January:1 February:2 March:3] map[January:1 March:3] 复制代码
上面的代码,咱们使用range
将m
的键值对循环赋值给了month
,而后删除month
其中一个键值对,经过打印的结果能够看出,m
没有改变。这就实现了真正的拷贝。 关于Map
的使用就讲到这,欢迎你们评论交流!
原创文章,若需转载请注明出处!
欢迎扫码关注公众号「Golang来啦」或者移步 seekload.net ,查看更多精彩文章。
公众号「Golang来啦」给你准备了一份神秘学习大礼包,后台回复【电子书】领取!