概述
在Go语言中 一个map就是一个哈希表的引用 map类型可以写为map[K]V
K对应的key必须是支持==比较运算符的数据类型
浮点数类型也是支持相等运算符比较的 但不要将浮点数用做key类型
创建map
- 内置make函数
tmap:=make(map[string]int)
- 字面量
tmap:=map[string]int{"alice":31,"charlie":34}
//字面量创建空map
tmap:=map[string]int{}
map操作
访问/查询/删除(delete)map中的元素都是安全的操作 即使map中不包含该K 查找失败会返回V对应的零值
map中的元素不是变量 不能对map元素进行取地址操作 这是因为map随K变大会重新分配内存空间 导致原来的地址无效!
_=&tmap["alice"]//compile error:cannot take address of map element
- 遍历map 使用for ... range遍历map 每次的顺序是不定的
- 查看K是否存在
if age, ok := tmap["bob"]; !ok { /* ... */ }
值为nil的map&&map之间的比较
- 值为nil的map表示没有引用任何哈希表
- 查找/删除/len/range操作都可以在nil的map上安全工作
- 向nil的map中存一个元素会导致panic 往map中存数据前要先创建map
- map之间不能进行==比较 map只能和nil进行==比较
*可以自己实现一个比较map的函数
func equal(x, y map[string]int) bool {
if len(x) != len(y) {
return false
}
for k, xv := range x {
if yv, ok := y[k]; !ok && yv != xv {
return false
}
}
return true
}
Set
Go语言中并没有提供一个set类型 但是map中的key也是不相同的 可以用map实现类似set的功能
func main() {
input := bufio.NewScanner(os.Stdin)
// Go程序员将这种忽略value的map当作一个字符串集合
seen := map[string]bool{}
for input.Scan() {
if !seen[input.Text()] {
seen[input.Text()] = true
fmt.Println(input.Text())
}
}
if err := input.Err(); err != nil {
fmt.Fprintf(os.Stderr, "dedup:%v\n", err)
os.Exit(1)
}
}
例子
- map[string]map[string]bool可以表示图
// 表示一张图 两个string中是否有边
var graph map[string]map[string]bool
// 为两个string添加一个连线
// 惰性初始化map 每个值在首次作为key时才初始化
// addEdge显示了如何让map为零值也能正常工作
func addEdge(from, to string) {
// 查找nil的map是安全操作 只有给nil的map添加元素才会引起panic
edges := graph[from]
if edges == nil {
edges = make(map[string]bool)
graph[from] = edges
}
edges[to] = true
}
func hasEdge(from, to string) bool {
return graph[from][to]
}
- 辅助函数k将不可比较的类型变为可以比较的K
第一步 定义一个辅助函数k 将slice转为map对应的string类型的key 确保只有x和y相等时k(x) == k(y)才成立
第二步 创建一个key为string类型的map 在每次对map操作时先用k辅助函数将slice转化为string类型
var m = make(map[string]int)
//辅助函数k(x)也不一定是字符串类型 它可以返回任何可比较的类型 例如整数/数组/结构体等
func k(list []string) string { return fmt.Sprintf("%q", list) }
func Add(list []string) { m[k(list)]++ }
func Count(list []string) int { return m[k(list)] }
- 统计输入中每个Unicode码点出现的次数
func main() {
counts := make(map[rune]int)
var utflen [utf8.UTFMax + 1]int
invalid := 0
in := bufio.NewReader(os.Stdin)
for i := 0; i < 10; i++ {
r, n, err := in.ReadRune()
if err == io.EOF {
break
}
if err != nil {
fmt.Fprintf(os.Stderr, "charcount %v\n", err)
os.Exit(1)
}
if r == unicode.ReplacementChar && n == 1 {
invalid++
continue
}
counts[r]++
utflen[n]++
}
fmt.Printf("rune\tcount\n")
for c, n := range counts {
fmt.Printf("%q\t%d\n", c, n)
}
fmt.Printf("len\tcount\n")
for i, v := range utflen {
if i > 0 {
fmt.Printf("%d\t%d\n", i, v)
}
if invalid > 0 {
fmt.Printf("\n%d invalid UTF-8 characters\n", invalid)
}
}
}