美文网首页
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