散列值的作用
映射中数据的删除
// 创建一个键为字符串类型,值为整形的map m1 := map[string]int{"last":2019, "now":2020} // 获取map中的元素 fmt.Println(m1["last"]) // 2019 fmt.Println(m1["now"]) // 2020 // 使用字面量创建一个空map m2 := map[string]string{} fmt.Println(m2) // map[]
映射的键的类型可以是内置类型,也可以是结构类型,但这个类型必须可以使用==运算符做比较。切片,函数以及包含切片的结构类型由于具有引用语义,不能作为映射的键,否则会造成编译错误。
m1 := make(map[int] string) // map的容量使用默认值 m1[1] = "lioney" m2 := make(map[int] string, 10) // map的容量使用给定值 m2[1] = "carlos" fmt.Println(m1[1]) // lioney fmt.Println(m2[1]) // carlos
package main import "fmt" func main() { // 创建一个空的map m1 := make(map[int] string) // 向map中添加元素 m1[1] = "lioney" m1[2] = "carlos" m1[3] = "tom" // 从map中删除键为3的元素 delete(m1, 3) // len()表示map中键值对的数量 fmt.Println("len=", len(m1)) // 遍历map for k, v := range m1 { fmt.Println("key=", k, "value=", v) } }
上述代码编译后运行结果如下:
len= 2 key= 2 value= carlos key= 1 value= lioney Process finished with exit code 0
和切片类似,映射在使用时必须对其底层数组进行初始化,要么使用make进行初始化,要么使用字面量初始化,如果只是简单地声明了一个map,而没有进行初始化,就是nil映射,是不能对其赋值的,请看下面代码:
// 声明一个map var colors map[string]string // 将red加入colors colors["red"] = "#da137" // panic: assignment to entry in nil map
可以做如下修改:
// 声明一个map var colors map[string]string // 对map进行初始化 colors = make(map[string]string) // 将red加入colors colors["red"] = "#da137" // no panic or error
也可以做如下修改:
// 使用字面量创建要给空map colors := map[string]string{} // 将red加入colors colors["red"] = "#da137" // no panic or error
强烈推荐使用第二种,因为用字面量创建map比较简洁而且比较快
在Go语言里,通过键来索引值时,即便这个键不存在也会返回一个值,有时候我们需要判断获取到的值是否时默认的零值,代码如下所示。
// 使用字面量创建一个空map colors := map[string]string{} // 将red加入colors colors["red"] = "#da137" // 获取blue对应的值并判断是否为零值 value1, exists := colors["blue"] if exists { fmt.Println(value1) } // 也可以通过值直接判断是否为零值 value2 := colors["blue"] if value2 != "" { fmt.Println(value2) }
package main import ( "fmt" "unsafe" ) func foo(m map[string]string) { // 打印参数的大小 fmt.Println("参数大小", unsafe.Sizeof(m)) // 删除键为green的元素 delete(m, "green") } func main() { // 使用字面量创建一个空map colors := map[string]string{} // 将red加入colors colors["red"] = "#da137" colors["coral"] = "#ff7f50" colors["green"] = "#228b22" // 调用foo函数 foo(colors) // 遍历打印map for k, v := range colors { fmt.Println("key=", k, "value=", v) } }
编译并运行以上代码,结果如下:
参数大小 8 key= red value= #da137 key= coral value= #ff7f50 Process finished with exit code 0
映射是引用类型的数据结构,在函数间传递映射的时候,不会拷贝映射底层的数据,从上面代码的运行结果可以看出,只传递了一个8字节大小的指针,实际上,map类型就是一个指针类型,函数对映射的操作都是通过这个指针间接进行的,因此对映射中数据的修改,其它引用到该映射的地方也能感知到。
package main import "fmt" type User struct { name string age int } func main() { m := make(map[int]User) user := User{ name: "lioney", age: 18, } // 将user加入到map中 m[1] = user // 修改user // 不能通过map引用直接修改!!! //m[1].age = 2 // error: cannot assign to struct field m[1].age in map // 必须整体替换 user.age = 2 m[1] = user fmt.Println(m) }
Go语言内置的map不是并发安全的,若是在并发场景下以共享的形式访问map中的元素,必须加锁,要想使用并发安全的map,可以使用Go语言标准库中sync包下提供的map。
我是lioney,年轻的后端攻城狮一枚,爱钻研,爱技术,爱分享。
个人笔记,整理不易,感谢阅读、点赞和收藏。
文章有任何问题欢迎大家指出,也欢迎大家一起交流后端各种问题!