7.5.1 map创建
要求所有的key的数据类型相同,所有value数据类型相同(注:key与value可以有不同的数据类型)
// 1 字面值{m1 := map[string]string{"m1": "v1", // 定义时指定的初始key/value, 后面可以继续添加}_ = m1}// 2 使用make函数{m2 := make(map[string]string) // 创建时,里面不含元素,元素都需要后续添加m2["m2"] = "v2" // 添加元素_ = m2}// 定义一个空的map{m3 := map[string]string{}m4 := make(map[string]string)_ = m3_ = m4}
7.5.2 map中key的类型
map中的每个key在keys的集合中是唯一的,而且需要支持 == or != 操作
key的常用类型:int, rune, string, 结构体(每个元素需要支持 == or != 操作), 指针, 基于这些类型自定义的类型
// m0 可以, key类型为string, 支持 == 比较操作{var m0 map[string]string // 定义map类型变量m0,key的类型为string,value的类型stringfmt.Println(m0)}// m1 不可以, []byte是slice,不支持 == != 操作,不可以作为map key的数据类型{//var m1 map[[]byte]string // 报错: invalid map key type []byte//fmt.Println(m1)// 准确说slice类型只能与nil比较,其他的都不可以,可以通过如下测试:// var b1,b2 []byte// fmt.Println(b1==b2) // 报错: invalid operation: b1 == b2 (slice can only be compared to nil)}// m2 可以, interface{}类型可以作为key,但是需要加入的key的类型是可以比较的{var m2 map[interface{}]stringm2 = make(map[interface{}]string)//m2[[]byte("k2")]="v2" // panic: runtime error: hash of unhashable type []uint8m2[123] = "123"m2[12.3] = "123"fmt.Println(m2)}// m3 可以, 数组支持比较{a3 := [3]int{1, 2, 3}var m3 map[[3]int]stringm3 = make(map[[3]int]string)m3[a3] = "m3"fmt.Println(m3)}// m4 可以,book1里面的元素都是支持== !={type book1 struct {name string}var m4 map[book1]stringfmt.Println(m4)}// m5 不可以, text元素类型为[]byte, 不满足key的要求{// type book2 struct {// name string// text []byte //没有这个就可以// }//var m5 map[book2]string //invalid map key type book2//fmt.Println(m5)}
7.5.3 map的增删改
// 创建m := map[string]string{"a": "va","b": "vb",}fmt.Println(len(m)) // len(m) 获得m中key/value对的个数// 增加,修改{// k不存在为增加,k存在为修改m["c"] = ""m["c"] = "11" // 重复增加(key相同),使用新的值覆盖fmt.Printf("%#v %#v\n", m, len(m)) // map[string]string{"a":"va", "b":"vb", "c":"11"} 3}// 查{// v := m[k] // 从m中取键k对应的值给v,如果k在m中不存在,则将value类型的零值赋值给v// v, ok := m[k] // 从m中取键k对应的值给v,如果k存在,ok=true,如果k不存在,将value类型的零值赋值给v同时ok=false// 查1 - 元素不存在v1 := m["x"] //v2, ok2 := m["x"]fmt.Printf("%#v %#v %#v\n", v1, v2, ok2) // "" "" false// 查2 - 元素存在v3 := m["a"]v4, ok4 := m["a"]fmt.Printf("%#v %#v %#v\n", v3, v4, ok4) //"va" "va" true}// 删, 使用内置函数删除k/v对{// delete(m, k) 将k以及k对应的v从m中删掉;如果k不在m中,不执行任何操作delete(m, "x") // 删除不存在的key,原m不影响delete(m, "a") // 删除存在的keyfmt.Printf("%#v %#v\n", m, len(m)) // map[string]string{"b":"vb", "c":"11"} 2delete(m, "a") // 重复删除不报错,m无影响fmt.Printf("%#v %#v\n", m, len(m)) /// map[string]string{"b":"vb", "c":"11"} 2}
7.5.4 map的遍历
- 遍历的顺序是随机的
- 使用for range遍历的时候,k,v使用的同一块内存,这也是容易出现错误的地方
7.5.5 map遍历易错点举例
由于遍历的时候,遍历v使用的同一块地址,同时这块地址是临时分配的。虽然v的地址没有变化,但v的内容在一直变化,当遍历完成后,v的内容是map遍历时最后遍历的元素的值(map遍历无序,每次不确定哪个元素是最后一个元素)。当程序将v的地址放入到slice中的时候,slice在不断地v的地址插入,由于v一直是那块地址,因此slice中的每个元素记录的都是v的地址。因此当打印slice中的内容的时候,都是同一个值
