Skip to content

介绍

所谓的映射表其实就是: 键值对, 在不同的编程语言中有不同的叫法:

  • Python 中叫做: 字典 dict
  • JavaScript 中叫做: 对象 object
  • Lua 中叫做: 元表 table
  • Java 中叫做: 哈希表 HashMap
go
package main

import "fmt"

func main() {
  // 定义一个映射表:
  // 变量名 := map[key-type]value-type {}
	scores := map[string]int {
		// key: value 合起来叫做: 键值对/字段
		// key:   叫做: 键, 键名, 属性名, 字段名
		// value: 叫做: 值, 键值, 属性值, 字段值
		"zhangsan": 78,
		"lisi":     88,
	}

	fmt.Println(scores)
}

初始化

go
package main

import "fmt"

func main() {
	// 1.声明时不赋值
	m1 := map[string]int{}
	m1["a"] = 1
	m1["b"] = 2
	m1["c"] = 3
	fmt.Println("m1:", m1)

	// 2.声明时直接赋值
	m2 := map[string]int{
		"a": 1,
		"b": 2,
		"c": 3,
	}
	fmt.Println("m2:", m2)

	// 2.使用 make 函数创建映射表
	m3 := make(map[string]int)
	m3["a"] = 1
	m3["b"] = 2
	m3["c"] = 3
	fmt.Println("m3:", m3)
}

map 数据的特点

  1. map 是一种非线性列表(或者叫: 无序列表)集合
  2. map 存储的是 key-value 键值对
  3. map 中的 key 具有唯一性
  4. map 中的 key 可以是任意可比较相等的数据类型: int/float/bool/string 等
  5. map 中的 value 可以是任意类型
go
package main

import "fmt"

func main() {
  // key 可以是 string
	mp1 := map[string]string{
		"a": "1",
		"b": "2",
	}
	fmt.Println(mp1)

  // key 可以是 int/bool/float 等等
  // 但是用的最多的还是 string
	mp2 := map[int]int{
		1: 11,
		2: 22,
	}
	fmt.Println(mp2)

	// 值可以是 切片
	mp3 := map[string][]int{
		"startPos": {0, 0},
		"endPos":   {5, 5},
	}
	fmt.Println(mp3)

	// 值可以是 map
	mp4 := map[string]map[string]int{
		"startPos": {
			"x": 0,
			"y": 0,
		},
		"endPos": {
			"x": 100,
			"y": 100,
		},
	}
	fmt.Println(mp4)
}

不能做为 key 的数据类型

由于映射表中不能有两个相同的 key, 否则会覆盖, 所以:只有可以比较的数据类型 才能作为 key, 不能比较的数据类型就无法作为映射表的 key, 不能比较是否相等的数据类型有:

  • 函数
  • 数组
  • 切片
  • map
go
package main

import "fmt"

func main() {
	s1 := []int{1}
	s2 := []int{1}
	// invalid operation: s1 == s2 (slice can only be compared to nil)
	// fmt.Println(s1 == s2)

	// invalid map key type []int
	m := map[[]int]int{
		s1: 1,
		s2: 2,
	}
	fmt.Println(m)
}

操作 map

go
package main

import "fmt"

func main() {
	m := map[string]int{
		"a": 1,
		"b": 2,
		"c": 3,
	}

	// 获取字段的个数
	fmt.Println("获取字段的个数:", len(m)) // 3

	// 获取字段
	fmt.Println("工具key获取对应字段的值:", m["a"]) // 1

	// 枚举所有字段, for range 枚举的顺序是随机的
	for k, v := range m {
		fmt.Printf("遍历字段 k=%v, v=%v \n", k, v)
	}

	// 增加字段
	m["d"] = 4
	fmt.Println("增加字段后:", m) // map[a:1 b:2 c:3 d:4]

	// 修改字段
	m["a"] = 11
	fmt.Println("修改字段后:", m) // map[a:11 b:2 c:3 d:4]

	// 删除字段
	delete(m, "b")
	fmt.Println("删除字段后:", m) // map[a:11 c:3 d:4]
}

访问字段 & 访问不存在的字段

在 go 语言中, 并不像 JS 那样会 隐式类型转换, 在判断的时候, 必须要是 bool 值

go
package main

func main() {
	m := map[string]int{
		"test": 1,
	}

	// 反面案例: 这样肯定是不行的,
  // 这个 m["test"] 表达式结果不是布尔值
	// if m["test"] {
	// }

	// 这样是可以的, 因为这个表达式的结果是布尔值
	if m["test"] == 1 {
	}
}
go
package main

import "fmt"

func main() {
	m := map[string]int{
		"a": 1,
		"b": 2,
		"c": 3,
	}

	// 值, 是否是否存在的布尔值
	// 如果字段不存在, 默认的值是 0(类型的默认值)
	c, cExist := m["c"]
	d, dExist := m["d"]


  // 语法糖: 可以写成这样:
  // if c, exist := m["c"]; exist {
  //   fmt.Println("c:", c, exist) // c: 3 true
  // }

	fmt.Println("c:", c, cExist) // c: 3 true
	fmt.Println("d:", d, dExist) // d: 0 false
}

map 中存储不同类型的值

在描述一个物体的信息, 可能需要多个类型的值, 比如一个人的名字应该是 字符串, 身高体重应该是 int/float 可以计算的数据类型

go
package main

import "fmt"

func main() {
	// any 类型表示: 不限制类型/可以是任何类型
	user := map[string]any{
		"name":   "张三",
		"age":    18,
		"isMale": true,
	}

	fmt.Println(user)
}

Released under the MIT License.