美文网首页
go学习笔记(映射)

go学习笔记(映射)

作者: 小东班吉 | 来源:发表于2020-01-06 10:34 被阅读0次

    映射

    映射是一种用来存储一系列无序键值对的数据结构

    1. 映射的底层存储结构。
    image-20200105143952464.png
    // A header for a Go map.
    type hmap struct {
        // Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
        // Make sure this stays in sync with the compiler's definition.
        count     int // # live cells == size of map.  Must be first (used by len() builtin)
        flags     uint8
        B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
        noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
        hash0     uint32 // hash seed
    
        buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
        oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
        nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
    
        extra *mapextra // optional fields
    }
    
    // mapextra holds fields that are not present on all maps.
    type mapextra struct {
        // If both key and elem do not contain pointers and are inline, then we mark bucket
        // type as containing no pointers. This avoids scanning such maps.
        // However, bmap.overflow is a pointer. In order to keep overflow buckets
        // alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow.
        // overflow and oldoverflow are only used if key and elem do not contain pointers.
        // overflow contains overflow buckets for hmap.buckets.
        // oldoverflow contains overflow buckets for hmap.oldbuckets.
        // The indirection allows to store a pointer to the slice in hiter.
        overflow    *[]*bmap
        oldoverflow *[]*bmap
    
        // nextOverflow holds a pointer to a free overflow bucket.
        nextOverflow *bmap
    }
    
    // A bucket for a Go map.
    type bmap struct {
        // tophash generally contains the top byte of the hash value
        // for each key in this bucket. If tophash[0] < minTopHash,
        // tophash[0] is a bucket evacuation state instead.
        tophash [bucketCnt]uint8
        // Followed by bucketCnt keys and then bucketCnt elems.
        // NOTE: packing all the keys together and then all the elems together makes the
        // code a bit more complicated than alternating key/elem/key/elem/... but it allows
        // us to eliminate padding which would be needed for, e.g., map[int64]int8.
        // Followed by an overflow pointer.
    }
    

    可以看出一个映射里包含了很多个hash桶(bucket),每个桶里存储了hash值的高8位以及8个key和8个value,key的hash值的低8位确定key在桶里的位置。每次查找,删除键值对的时候都把需要把key传给hash函数,由hash函数生成一个索引,这个索引最终将键值对分布到所有可用的桶里,具体的底层数据结构另说。

    1. 创建初始化使用
    dict := make(map[string]int) //make函数创建一个无须集合。
    dict := map[string][int]{"chujiu":20,"dong":30} //字面量初始化一个映射
    dict1 := map[string][int]{}//初始化一个空的map
    dict := map[[]string]int{} //这会抛出一个错误,map的key理论上可以用任何类型作为key,但有引用类型除外,基本上可以做==等值比较的类型都可以作为key,这里用切片作为key是不行的,引用,函数,包含切片的结构类型都不行。
    //Invalid map key type: the comparison operators == and != must be fully defined for key type
    
    var dict2 map[string]int //声明一个为nil的映射,这和空的映射并不相等。也不能赋值
    dict2["age"] = 2 //针对nil的映射存储值会发生一个panic错误。 assignment to entry in nil map
    dict1["age"] = 2 //这个是可以的,初始化的时候是一个空的映射。
    dict2 = dict1 //这样也是可以的。但这是一个引用操作,对dict2操作任何修改dict1都会受到影响。因为指向的是同一个bucket数组。
    
    //从映射中取出一个值来,即使这个key不存在,也会返回一个对应的零值。
    value := dict1["num"] //即使key不存在,value也会返回一个0
    if value == 0 {
      fmt.Print(value)
    }
    for key, value := range dict1 {
      fmt.Println("key:"+key, ",value:", value)
    }
    
    delete(dict1, "age")//删除一个映射中的key,没有返回值,函数间传递是引用传递,并不会拷贝一个新的映射集合,也就是当在函数内部对映射做出了修改后,原来的映射也会受到影响。
    

    相关文章

      网友评论

          本文标题:go学习笔记(映射)

          本文链接:https://www.haomeiwen.com/subject/rxwhactx.html