28、Go 复合数据类型 - map 映射
hi,我是温新
map 简介
**map(映射)
是一种数据结构,用于存储一系列无序的键值对,映射基于键来存储值。**把它当前 PHP 中的关联数组来就看就容易理解了。
map 是一种集合,可以像遍历数组或切片那样来遍历它。由于 map 是由 Hash 表实现的,因此对 map 的读取顺序是不固定的。
关于 map 需要注意的是:
1、map 是无序的,每次打印的 map 都会不一样,map 必须通过 key 获取值;
2、map 的长度是不固定的,和切片可以扩展;
3、同一个 map 中的 key 必须唯一;
4、map 的值可以是任何数据类型。
map 创建
可以使用 var 关键字来定义 map,也可以使用内置函数 make。
使用 var 关键字定义 map
// 格式
var variableName map[keyType]valueType
使用 var 关键字声明 map时,未初始化的 map 的默认值是 nil。nil map 不能存放键值对。若要使用 map 存储键值对,则必须在声明时初始化,或使用 make 函数分配到内存空间。案例如下:
package main
import "fmt"
func main() {
// 声明一个 map
var myMap map[int]int
fmt.Println(myMap) // []
// map 赋值
myMap = map[int]int{1: 100, 2: 200}
fmt.Println(myMap)
}
使用 make 函数
// 格式
变量名 := make(map[keyType]valueType)
使用 make 函数或使用映射字面量创建 map 是最常见的方式,案例如下:
package main
import "fmt"
func main() {
// 创建一个映射,键是 string 类型,值是 int 类型
myMap := make(map[string]int)
// 赋值
myMap["lucy"] = 3
myMap["jack"] = 4
fmt.Println(myMap)
}
map 初始化赋值
package main
import "fmt"
func main() {
// 字面量初始化并赋值
colors := map[string]string{
"red": "#da1337",
"orange": "#e956a22",
}
fmt.Println(colors)
}
map 的使用
元素赋值
package main
import "fmt"
func main() {
colors := map[string]string{}
// 元素赋值
colors["red"] = "#da1337"
fmt.Println(colors)
}
下面是报错的案例。通过声明一个未初始化的 map 可以创建一个值为 nil,但不能用于存储键值对,否则报错,案例如下:
package main
import "fmt"
func main() {
// 声明映射,不赋值,将得到一个 nil
var colors map[string]string
fmt.Println(colors)
// 赋值
colors["red"] = "#da1337"
}
运行代码时,将会报错,信息如下:
panic: assignment to entry in nil map
查找与遍历
从 Map 取值有两种方式,一种是获得值以及一个表示这个键是否存在的标志;另一种是只返回对应的值,再判断这个值是否为零值,以此来确保键存在。
package main
import "fmt"
func main() {
names := map[string]int{
"lucy": 100,
"jack": 90,
}
value, exists := names["lucy"]
if exists {
fmt.Println(value)
}
// 不存在的 key
v, e := names["foo"]
fmt.Println(v, e) // 返回值 0 false
}
通过 key 可以获取 map 中对应的 value 值。当 key 不存在时,会得到该 value 值类型的默认值,如 int 将得到 0,string 将得到空,而程序不会报错。因此可以通过value, exists := map[key]
获取 value 是否存在。
下面是遍历 map 的案例
package main
import "fmt"
func main() {
person := map[string]string{
"name": "王美丽",
"age": "19",
"gender": "",
}
for key, value := range person {
if value != "" {
fmt.Printf("Key: %s Value:%s]\n", key, value)
}
}
}
删除元素
内置函数 delete(map, key)
用于删除 map 的某个元素。删除函数不返回任何值。
package main
import "fmt"
func main() {
person := map[string]string{
"name": "王美丽",
"age": "19",
"gender": "",
}
delete(person, "gender")
delete(person, "nickname")
fmt.Println(person)
}
删除一个不存在的 key 时,不会发生任何影响,也就是什么事都没有。但是当传入的 map 变量的值是 nil 时,将导致程序抛出 panic 异常。
将 map 传递给函数
在函数间传递 map 并不会制造出该 map 的一个副本。实际上,当传递映射给一个函数,并对这个映射做修改时,所有对这个映射的引用都会受到影响。
package main
import "fmt"
func main() {
person := map[string]string{
"name": "王美丽",
"age": "19",
}
// 遍历 map
for key, value := range person {
fmt.Printf("Key: %s Value:%s]\n", key, value)
}
// 删除指定的 key
removeAttr(person, "age")
for key, value := range person {
fmt.Printf("Key: %s Value:%s]\n", key, value)
}
}
// 删除一个属性
func removeAttr(person map[string]string, key string) {
delete(person, key)
}
map 是引用类型
map 是一个引用类型,将一个 map 赋值给一个新变量时,它们指向同一块内存。因此无论修改哪一个变量的内容都会影响另外一个。
package main
import "fmt"
func main() {
person := map[string]string{
"name": "王美丽",
"age": "19",
}
fmt.Println("原始数据", person)
p1 := person
p1["age"] = "20"
fmt.Println("p1 变量", p1)
fmt.Println("person 受到 p1 的影响", person)
}
输出结果
原始数据 map[age:19 name:王美丽]
p1 变量 map[age:20 name:王美丽]
person 受到 p1 的影响 map[age:20 name:王美丽]