Go Map -- 就要学习 Go 语言

前言

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类型为stringvalue类型为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?固然是有为nilMap:学习

var month map[string]int
fmt.Println(month == nil)    // 输出:true
复制代码

对于nilmap是不能存取键值对的,不然就会报错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的零值就是nilMap就是底层Hash表的引用。 Mapkey能够是内置类型,也能够是结构类型,只要可使用 == 运算符作比较,均可以做为key切片函数以及包含切片的结构类型,这些类型因为具备引用语义,不能做为key,使用这些类型会形成编译错误:.net

month := map[[]string]int{}
// 编译错误:invalid map key type []string
复制代码

对于Mapvalue来讲,就没有类型限制,固然也没有任何理由阻止用户使用切片做为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赋值给了名为slicekey。第二段代码是第一段代码的简写版本。

如何使用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是不容许重复的。 获取一个不存在的keyvalue的时候,会返回值类型对应的零值,这个时候,咱们就不知道是存在一个值为零值的键值对仍是键值对就根本不存在。好在,Map给咱们提供了方法:

february,exists := m["February"]
fmt.Println(february,exists)   // 输出:0 false
复制代码

获取值的时候多了一个返回值,第一个返回值是value,第二个返回值是boolean类型变量,表示value是否存在。这给咱们判断一个key是否存在就提供了很大便利。

delete--删除键值对

不像SliceGo为咱们提供了删除键值对的功能--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
复制代码

可使用空白操做符_忽略返回的keyvalue。屡次执行代码的时候,你会发现,返回值的顺序有多是不同的,也就是说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拷贝时,mmonth是共享底层数据的,改变其中一方数据,另外一方也会随之改变。相似,在函数间传递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]
复制代码

上面的代码,咱们使用rangem的键值对循环赋值给了month,而后删除month其中一个键值对,经过打印的结果能够看出,m没有改变。这就实现了真正的拷贝。 关于Map的使用就讲到这,欢迎你们评论交流!


(全文完)

原创文章,若需转载请注明出处!
欢迎扫码关注公众号「Golang来啦」或者移步 seekload.net ,查看更多精彩文章。

公众号「Golang来啦」给你准备了一份神秘学习大礼包,后台回复【电子书】领取!

公众号二维码