Map


概述

在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)
    }
}

例子

  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]
}
  1. 辅助函数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)] }
  1. 统计输入中每个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)
        }
    }
}

你可能感兴趣的:(Map)