码迷,mamicode.com
首页 > 其他好文 > 详细

go map 基本操作

时间:2019-03-10 09:20:25      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:2.3   nil   删掉   make   []   str   panic   分配   name   

目录

  • map中的key的数据类型
    • key的几种数据类型举例
  • map基本操作
    • map创建
    • map增删改查
    • map遍历
      • map遍历易错点举例

  • go中的map是hash表的一个引用,类型写为:map[key]value,其中的key, value分别对应一种数据类型,如map[string]string
  • 要求所有的key的数据类型相同,所有value数据类型相同(注:key与value可以有不同的数据类型)

map中的key的数据类型

  • map中的每个key在keys的集合中是唯一的,而且需要支持 == or != 操作
  • key的常用类型:int, rune, string, 结构体(每个元素需要支持 == or != 操作), 指针, 基于这些类型自定义的类型

    float32/64 类型从语法上可以作为key类型,但是实际一般不作为key,因为其类型有误差

key的几种数据类型举例

    // m0 可以, key类型为string, 支持 == 比较操作
    {
        var m0 map[string]string // 定义map类型变量m0,key的类型为string,value的类型string
        fmt.Println(m0)
    }

    // m1 不可以, []byte是slice,不支持 == != 操作,不可以作为map key的数据类型
    {
        //var m1 map[[]byte]string // 报错: invalid map key type []byte
        //fmt.Println(m1)

        // 准确说slice类型只能与nil比较,其他的都不可以,可以通过如下测试:
        // var b1,b2 []byte
        // fmt.Println(b1==b2) // 报错: invalid operation: b1 == b2 (slice can only be compared to nil)
    }

    // m2 可以, interface{}类型可以作为key,但是需要加入的key的类型是可以比较的
    {
        var m2 map[interface{}]string
        m2 = make(map[interface{}]string)
        //m2[[]byte("k2")]="v2" // panic: runtime error: hash of unhashable type []uint8
        m2[123] = "123"
        m2[12.3] = "123"
        fmt.Println(m2)
    }

    // m3 可以, 数组支持比较
    {
        a3 := [3]int{1, 2, 3}
        var m3 map[[3]int]string
        m3 = make(map[[3]int]string)
        m3[a3] = "m3"
        fmt.Println(m3)
    }

    // m4 可以,book1里面的元素都是支持== !=
    {
        type book1 struct {
            name string
        }
        var m4 map[book1]string
        fmt.Println(m4)
    }

    // m5 不可以, text元素类型为[]byte, 不满足key的要求
    {
        // type book2 struct {
        //  name string
        //  text []byte //没有这个就可以
        // }
        //var m5 map[book2]string //invalid map key type book2
        //fmt.Println(m5)
    }

map基本操作

map创建

  • 两种创建的方式:一是通过字面值;二是通过make函数
    // 1 字面值
    {
        m1 := map[string]string{
            "m1": "v1", // 定义时指定的初始key/value, 后面可以继续添加
        }
        _ = m1

    }

    // 2 使用make函数
    {
        m2 := make(map[string]string) // 创建时,里面不含元素,元素都需要后续添加
        m2["m2"] = "v2"               // 添加元素
        _ = m2

    }

    // 定义一个空的map
    {
        m3 := map[string]string{}
        m4 := make(map[string]string)
        _ = m3
        _ = m4
    }

map增删改查

    // 创建
    m := map[string]string{
        "a": "va",
        "b": "vb",
    }
    fmt.Println(len(m)) // len(m) 获得m中key/value对的个数

    // 增加,修改
    {
        // k不存在为增加,k存在为修改
        m["c"] = ""
        m["c"] = "11"                      // 重复增加(key相同),使用新的值覆盖
        fmt.Printf("%#v %#v\n", m, len(m)) // map[string]string{"a":"va", "b":"vb", "c":"11"} 3
    }

    // 查
    {
        // v := m[k] // 从m中取键k对应的值给v,如果k在m中不存在,则将value类型的零值赋值给v
        // v, ok := m[k] // 从m中取键k对应的值给v,如果k存在,ok=true,如果k不存在,将value类型的零值赋值给v同时ok=false
        // 查1 - 元素不存在
        v1 := m["x"] //
        v2, ok2 := m["x"]
        fmt.Printf("%#v %#v %#v\n", v1, v2, ok2) // "" "" false

        // 查2 - 元素存在
        v3 := m["a"]
        v4, ok4 := m["a"]
        fmt.Printf("%#v %#v %#v\n", v3, v4, ok4) //"va" "va" true
    }

    // 删, 使用内置函数删除k/v对
    {
        // delete(m, k) 将k以及k对应的v从m中删掉;如果k不在m中,不执行任何操作
        delete(m, "x")                     // 删除不存在的key,原m不影响
        delete(m, "a")                     // 删除存在的key
        fmt.Printf("%#v %#v\n", m, len(m)) // map[string]string{"b":"vb", "c":"11"} 2
        delete(m, "a")                     // 重复删除不报错,m无影响
        fmt.Printf("%#v %#v\n", m, len(m)) /// map[string]string{"b":"vb", "c":"11"} 2
    }

map遍历

  • 遍历的顺序是随机的
  • 使用for range遍历的时候,k,v使用的同一块内存,这也是容易出现错误的地方
    m := map[string]int{
        "a": 1,
        "b": 2,
    }
    for k, v := range m {
        fmt.Printf("k:[%v].v:[%v]\n", k, v) // 输出k,v值
    }

map遍历易错点举例

由于遍历的时候,遍历v使用的同一块地址,同时这块地址是临时分配的。虽然v的地址没有变化,但v的内容在一直变化,当遍历完成后,v的内容是map遍历时最后遍历的元素的值(map遍历无序,每次不确定哪个元素是最后一个元素)。当程序将v的地址放入到slice中的时候,slice在不断地v的地址插入,由于v一直是那块地址,因此slice中的每个元素记录的都是v的地址。因此当打印slice中的内容的时候,都是同一个值

    m := map[string]int{
        "a": 1,
        "b": 2,
    }
    var bs []*int
    for k, v := range m {
        fmt.Printf("k:[%p].v:[%p]\n", &k, &v) // 这里的输出可以看到,k一直使用同一块内存,v也是这个状况
        bs = append(bs, &v) // 对v取了地址
    }

    // 输出
    for _, b := range bs {
        fmt.Println(*b) // 输出都是1或者都是2
    }

go map 基本操作

标签:2.3   nil   删掉   make   []   str   panic   分配   name   

原文地址:https://www.cnblogs.com/bingzhen/p/10503967.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!