Go语言入门-常用数据结构-映射-map
定义
概述
A map is an unordered group of elements of one type, called the element type, indexed by a set of unique keys of another type, called the key type. The value of an uninitialized map is nil.–字典是一种类型的无序元素组,称为元素类型,由唯一键(称为键类型)索引关联其他类型组成。 未初始化映射的值为nil。引用类型。
1.key必须是支持相等运算符 ("=="、"!=") 类型, 如 number、string、 pointer、array、struct,以及对应的 interface。值可以是任意类型,没有限制。
2. map类型的变量默认初始值为nil,需要使用make()函数来分配内存。或者使用初始化表达式,进行初始化。否则会发生panic(map类型的变量默认初始值为nil,需要使用make()函数来分配内存)
3. map是 not addressable不能直接修改value的值
4. 创建时准备足够内存,能够减少扩张的内存分配和重复哈希的动作。
5. map是并发不安全的。
map定义语法
var mapVal map[Type]Type //声明map
var mapVal map[Type]Type = map[Type]Type { //表达式初始化
"key1" : value1,
...
"keyN" : valueN,
}
var mapVal map[Type]Type = make(map[Type]Type) //make 不指定容量cpa
var mapVal map[Type]Type = make(map[Type]Type, cap) //make 指定容量
map定义示例
- 示例1
普通map的声明,实际引用的都是nil
func main() {
//普通map声明,不初始化
var map1 map[int]string
var map2 map[interface{}]string
//实际都是引用nil
fmt.Printf("%#v\n", map1)
//实际值都是引用nil
fmt.Printf("%#v\n", map2)
}
/**
output:
map[int]string(nil)
*/
- 示例2
map使用初始化表达式进行初始化。
func main() {
//声明
var map1 map[int]string
//表达式初始化
map1 = map[int]string{
1 : "hello",
2 : "hello1",
3 : "hello2",
}
fmt.Printf("%#v\n", map1)
//interface空接口可以映射int
//声明+表达式初始化
var map2 map[interface{}]int = map[interface{}]int{
1 : 1,
2 : 2,
3 : 3,
}
fmt.Printf("%#v\n", map2)
}
/**
output:
map[int]string{1:"hello", 2:"hello1", 3:"hello2"}
map[interface {}]int{1:1, 2:2, 3:3}
*/
- 示例3
通过make定义map不带容量 - TODO 不带容量的map初始map是多少?
func main() {
//make定义了一个map,该map初始没有值。
map1 := make(map[string]int)
fmt.Printf("%#v\n", map1)
map1["sdff"] = 1
map1["sdff2"] = 2
map1["sdff2"] = 3 //相同值会覆盖
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]int{}
map[string]int{"sdff":1, "sdff2":3}
*/
- 示例3
通过make定义map带容量
func main() {
//make定义了一个map,该map初始没有值,默认容量为10
map1 := make(map[string]int, 10)
fmt.Printf("%#v\n", map1)
map1["sdff"] = 1
map1["sdff2"] = 2
map1["sdff2"] = 3 //相同值会覆盖
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]int{}
map[string]int{"sdff":1, "sdff2":3}
*/
- 示例4
通过new创建map
func main() {
//只是创建了map的一个指针,返回一个指针,但是没有初始底层存储结构 因此new出来的map是不能直接用
var map1 = new(map[int]string)
fmt.Printf("%#v\n", map1)
//因为map1是指针因此需要使用*
//(*map1)[1] = "333" //panic: assignment to entry in nil map
//让map1指向map[int]string{} 就可以使用map1
map1 = &map[int]string{}
//因为map1是指针因此需要使用*
(*map1)[1] = "111"
fmt.Printf("%#v\n", map1)
}
/**
output:
&map[int]string(nil)
&map[int]string{1:"111"}
*/
new()出的map只是一个指针,没有给底层存储接口分配值,因此可以理解new返回一个没有初始化的map的地址,没有实际作用
使用
map添加key-value
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加键值 "123"--> "ABC"
map1["123"] = "ABC"
//添加键值 "124"--> "ABC"
map1["124"] = "ABC"
//添加键值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
//重复添加键值 "125"--> "ABCbbbNEW" 但是value和上次不一致
map1["125"] = "ABCbbbNEW"
//输出接口中key"125"只保留最后一次的value
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]string{}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
*/
添加相同的键,原来的键值value会被覆盖。
只能添加相同类型的元素
map查找key-value
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加键值 "123"--> "ABC"
map1["123"] = "ABC"
//添加键值 "124"--> "ABC"
map1["124"] = "ABC"
//添加键值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
//重复添加键值 "125"--> "ABCbbbNEW" 但是value和上次不一致
map1["125"] = "ABCbbbNEW"
//输出接口中key"125"只保留最后一次的value
fmt.Printf("%#v\n", map1)
//查找
key := "125"
v, ok := map1[key]
if ok {
fmt.Println("key:", key, "get value :", v)
} else {
fmt.Printf("%#v ", v)
fmt.Println("key:", key, "not found")
}
//没有查到到
key = "21333"
v, ok = map1[key]
if ok {
fmt.Println("key:", key, "get value :", v)
} else {
//如果没有查找到,返回value的类型的默认值。因此也可以不用ok进行判断
fmt.Printf("%#v ", v)
fmt.Println("key:", key, "not found")
}
}
/**
output:
map[string]string{}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
key: 125 get value : ABCbbbNEW
"" key: 21333 not found
*/
可以通过卫述语句进行判断是否获取到值
也可以通过value类型的值默认进行判断,但是这么判断前提是-默认值并能做元素值,否则会有二义性。
map删除key-value
map使用内建函数delete()来删除key-value关系,函数定义如下
func delete(m map[Type]Type1, key Type)
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加键值 "123"--> "ABC"
map1["123"] = "ABC"
//添加键值 "124"--> "ABC"
map1["124"] = "ABC"
//添加键值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
//重复添加键值 "125"--> "ABCbbbNEW" 但是value和上次不一致
map1["125"] = "ABCbbbNEW"
//输出接口中key"125"只保留最后一次的value
fmt.Printf("%#v\n", map1)
//删除一个不存在值
delete(map1, "rerr")
//不会报错正常打印元素值
fmt.Printf("%#v\n", map1)
//删除一个存在的值
delete(map1, "123")
//删除成功
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]string{}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
map[string]string{"124":"ABC", "125":"ABCbbbNEW"}
*/
删除一个不存在的元素键值也会成功。
map修改key-value
map的修改参考map添加key-value
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加键值 "123"--> "ABC"
map1["123"] = "ABC"
//添加键值 "124"--> "ABC"
map1["124"] = "ABC"
//添加键值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
//重复添加键值 "125"--> "ABCbbbNEW" 但是value和上次不一致
//也可以理解修改key为"125"的键值
map1["125"] = "ABCbbbNEW"
//输出接口中key"125"只保留最后一次的value
fmt.Printf("%#v\n", map1)
}
/**
output:
map[string]string{}
map[string]string{"123":"ABC", "124":"ABC", "125":"ABCbbbNEW"}
*/
map遍历key-value
fori 遍历
发现并不支持fori。。。。。。
~~func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加键值 "123"--> "ABC"
map1["123"] = "ABC"
//添加键值 "124"--> "ABC"
map1["124"] = "ABC"
//添加键值 "125"--> "ABCbbb"
for i := 0; i < len(map1); i++ {
//不知怎么写了
//写到这里发现并不支持
}
}~~
for…range遍历
- 示例1
func main() {
var map1 = make(map[string]string, 10)
fmt.Printf("%#v\n", map1)
//添加键值 "123"--> "ABC"
map1["123"] = "ABC"
//添加键值 "124"--> "ABC"
map1["124"] = "ABC"
map1["1266"] = "ABC"
//添加键值 "125"--> "ABCbbb"
map1["125"] = "ABCbbb"
for k, v := range map1 {
fmt.Printf("key:%#v value:%#v\n", k, v)
}
}
/**
output:
//输出结果是无序的
map[string]string{}
key:"1266" value:"ABC"
key:"125" value:"ABCbbb"
key:"123" value:"ABC"
key:"124" value:"ABC"
*/
for range循环遍历的map是无序的,因为map底层结构不是顺序存放的
for range获取的到值是值传递。map又不支持fori因此 map是 not addressable的
map 排序key-value
因为map是无序的,那么如何排序map呢?方法是获取到key的切片,然后通过遍历keys去获取value。
- 示例1
//排序
func main() {
var cap = 100
var map1 = make(map[int]string)
var tmpValue = 0
for i := 0; i < cap; i++ {
tmpValue = rand.Intn(100)
map1[tmpValue] = strconv.Itoa(tmpValue)
}
i := 0
//简单演示遍历的值是无需的
for k, v := range map1 {
if i < 3 {
fmt.Printf("key:%#v value:%#v\n", k, v)
}
i++
}
//遍历key把key存放到切片中
//此处 一定是 len=0 不然会有存在0的情况
keys := make([]int, 0, cap)
for k := range map1 {
keys = append(keys, k)
}
fmt.Println(keys)
//对keys排序
sort.Ints(keys)
fmt.Println("排序后:")
fmt.Println(keys)
//按照排序后key进行遍历。
for _, key := range keys {
fmt.Printf("%#v(%#v) ", key, map1[key])
}
fmt.Println()
}
/**
output:
key:51 value:"51"
key:96 value:"96"
key:6 value:"6"
[51 96 6 26 83 81 85 45 90 63 33 38 7 47 25 99 59 15 29 87 37 41 3 61 91 62 74 78 20 13 76 77 23 58 31 5 28 8 11 88 24 55 18 94 53 52 0 95 21 98 2 40 89 43 36 56 46 10 66 57]
排序后:
[0 2 3 5 6 7 8 10 11 13 15 18 20 21 23 24 25 26 28 29 31 33 36 37 38 40 41 43 45 46 47 51 52 53 55 56 57 58 59 61 62 63 66 74 76 77 78 81 83 85 87 88 89 90 91 94 95 96 98 99]
0("0") 2("2") 3("3") 5("5") 6("6") 7("7") 8("8") 10("10") 11("11") 13("13") 15("15") 18("18") 20("20") 21("21") 23("23") 24("24") 25("25") 26("26") 28("28") 29("29") 31("31") 33("33") 36("36") 37("37") 38("38") 40("40") 41("41") 43("43") 45("45") 46("46") 47("47") 51("51") 52("52") 53("53") 55("55") 56("56") 57("57") 58("58") 59("59") 61("61") 62("62") 63("63") 66("66") 74("74") 76("76") 77("77") 78("78") 81("81") 83("83") 85("85") 87("87") 88("88") 89("89") 90("90") 91("91") 94("94") 95("95") 96("96") 98("98") 99("99")
*/
map 并发
map可以再迭代的时候删除元素,新增元素
- 示例1
func main() {
var cap = 6
var map1 = make(map[int]string)
var tmpValue = 0
for i := 0; i < cap; i++ {
tmpValue = rand.Intn(100)
map1[tmpValue] = strconv.Itoa(tmpValue)
}
i := 0
for k, _ := range map1 {
fmt.Println("beg ==", map1)
i++
if i % 2 == 0 {
map1[i+k] = strconv.Itoa(i)
}
fmt.Println("end ==", map1)
}
fmt.Println("fin ==", map1)
}
/**
output:
beg == map[18:18 47:47 59:59 81:81 87:87]
end == map[18:18 47:47 59:59 81:81 87:87]
beg == map[18:18 47:47 59:59 81:81 87:87]
end == map[18:18 47:47 59:59 81:81 87:87 89:2]
beg == map[18:18 47:47 59:59 81:81 87:87 89:2]
end == map[18:18 47:47 59:59 81:81 87:87 89:2]
beg == map[18:18 47:47 59:59 81:81 87:87 89:2]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2]
beg == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2]
beg == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6]
beg == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6]
beg == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6]
end == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6 103:8]
fin == map[18:18 47:47 59:59 63:4 81:81 87:87 89:2 95:6 103:8]
*/
当map存在写操作时,不能并发的进行读写删除,否则进程崩溃,解决办法是使用sync.Map
- TODO补充例子