您现在的位置是:主页 > news > 卖衣服的网站建设/建站软件

卖衣服的网站建设/建站软件

admin2025/5/14 12:31:30news

简介卖衣服的网站建设,建站软件,公益永久免费主机,网站关键词书写步骤map前言map介绍使用示例map常见使用过程中的问题问题示例前言 关于更多map底层原理剖析,请点击这一篇博文Golang底层原理剖析之map map介绍 map 读取某个值时 - 返回结果可以为 value,bool 或者 value。注意后者,在key不存在时,会返回valu…

卖衣服的网站建设,建站软件,公益永久免费主机,网站关键词书写步骤map前言map介绍使用示例map常见使用过程中的问题问题示例前言 关于更多map底层原理剖析,请点击这一篇博文Golang底层原理剖析之map map介绍 map 读取某个值时 - 返回结果可以为 value,bool 或者 value。注意后者,在key不存在时,会返回valu…

map

  • 前言
  • map介绍
  • 使用示例
  • map常见使用过程中的问题
  • 问题示例

前言

关于更多map底层原理剖析,请点击这一篇博文Golang底层原理剖析之map

map介绍

  1. map 读取某个值时 - 返回结果可以为 value,bool 或者 value。注意后者,在key不存在时,会返回value对应类型的默认值
  2. map 的 range 方法需要注意 - key,value 或者 key。注意后者,可以和slice的使用结合起来
  3. map 的底层相关的实现 - 串联 初始化、赋值、扩容、读取、删除 这五个常见实现的背后知识点,详细参考示例代码链接与源码

使用示例

package mainimport "fmt"func mapper() {// var mp map[string]int 不会初始化mp := make(map[string]int)mp["Tom"] = 10age, ok := mp["Tom"]fmt.Println(age, ok)age1 := mp["Tom"]age2 := mp["Tom2"]fmt.Println(age1, age2)for key, value := range mp {fmt.Println(key, value)}for key := range mp {fmt.Println(key, mp[key])}var data = []int{1, 3, 5}for key := range data {fmt.Println(key, data[key])}
}// go tool compile -S map.go
func mapCompile() {m := make(map[string]int, 9)key := "test"m[key] = 1_, ok := m[key]if ok {delete(m, key)}
}/*源码文件:runtime/map.go初始化:makemap1. map中bucket的初始化 makeBucketArray2. overflow 的定义为哈希冲突的值,用链表法解决赋值:mapassign1. 不支持并发操作 h.flags&hashWriting2. key的alg算法包括两种,一个是equal,用于对比;另一个是hash,也就是哈希函数3. 位操作 h.flags ^= hashWriting 与 h.flags &^= hashWriting4. 根据hash找到bucket,遍历其链表下的8个bucket,对比hashtop值;如果key不在map中,判断是否需要扩容扩容:hashGrow1. 扩容时,会将原来的 buckets 搬运到 oldbuckets读取:mapaccess1. mapaccess1_fat 与 mapaccess2_fat 分别对应1个与2个返回值2. hash 分为低位与高位两部分,先通过低位快速找到bucket,再通过高位进一步查找,最后对比具体的key3. 访问到oldbuckets中的数据时,会迁移到buckets删除:mapdelete1. 引入了emptyOne与emptyRest,后者是为了加速查找
*/

map常见使用过程中的问题

  1. map 的 range 操作 - key、value 都是值复制
  2. map 如何保证按key的某个顺序遍历? - 分两次遍历,第一次取出所有的key并排序;第二次按排序后的key去遍历(这时你可以思考封装map和slice到一个结构体中)?
  3. map 的使用上,有什么要注意的? - 遍历时,尽量只修改或删除当前key,操作非当前的key会带来不可预知的结果
  4. 从 map 的设计上,我们可以学到 - Go语言对map底层的hmap做了很多层面的优化与封装,也屏蔽了很多实现的细节,适用于绝大多数的场景;而少部分有极高性能要求的场景,就需要深入到hmap中的相关细节。

问题示例

package mainimport ("fmt"
)func main() {mapAddr()mapModify()mapReplace()mapSet()mapMap()
}
func mapAddr() {var mp = map[int]int{1: 2, 2: 3, 3: 4}fmt.Printf("%p\n", &mp)fmt.Println("map range 1 start")// Tip 注意range中的k是不能保证顺序的for k, v := range mp {// Tip: k,v 是为了遍历、另外开辟内存保存的一对变量,不是map中key/value保存的地址fmt.Println(&k, &v)// Tip: 修改k/v后,不会生效k++v++// Tip 如果在这里加上一个delete操作,在k=1时会删除k=2的元素,然后就直接跳过元素2,遍历到元素3// map的delete是安全的,不会存在race等竞争问题,这里用到的k,v是值复制,删除是针对hmap的操作// delete(mp, k)// 编译错误,value不可寻址,因为这个在内部是频繁变化的// fmt.Printf("%p", &mp[k])}fmt.Println(mp)fmt.Println("map range 1 end")
}func mapModify() {// Tip: 如果map最终的size比较大,就放到初始化的make中,会减少hmap扩容带来的内容重新分配//var mp2 = make(map[int]int,1000)var mp2 = make(map[int]int)mp2[1] = 2mp2[2] = 3mp2[3] = 4fmt.Println("map range 2 start")for k, v := range mp2 {// Tip: 在range的过程中,如果不断扩容,何时退出是不确定的,是随机的,和是否需要sleep无关mp2[k+1] = v + 1// time.Sleep(10 * time.Millisecond)}fmt.Println(len(mp2))fmt.Println("map range 2 end")
}// https://stackoverflow.com/questions/45132563/idiomatic-way-of-renaming-keys-in-map-while-ranging-over-the-original-map
func mapReplace() {o := make(map[string]string) // original mapr := make(map[string]string) // replacement map original -> destination keyso["a"] = "x"o["b"] = "y"r["a"] = "1"r["b"] = "2"fmt.Println(o) // -> map[a:x b:y]// Tip: 因为o的k-v是在不断增加的,所以遍历何时结束是不确定的// 此时k可能为"1"或者"2",对应的r[k]不存在,//此时r这个map会创建key为1或2,value返回默认值空字符串 "",//所以结果会多一个key(r[k])为"",value为"x"或"y"的异常值for k, v := range o {o[r[k]] = v //想要实现<1,x><2,y>,但是结果是map[:x 1:x 2:y]}// Tip: 到这里,也许你会好奇,为什么每次运行的结果会不一致呢?map[:x 1:x 2:y]或者map[:y 1:x 2:y]// 1. 首先,我们要了解一点,遍历这个工作在hmap中是通过buckets进行的// 2. 因为多次运行的结果不一致,说明每一次运行时,分配的bucket是有随机的// 3. 仔细查看hmap这个结构体,我们不难发现hash0这个随机值,确认其对分配bucket的hash计算带来的影响// 4. 因为有hash0这个随机种子,所以遍历range是随机的delete(o, "a")delete(o, "b")fmt.Println(o)
}func mapSet() {// 空struct是不占用空间的,将struct{}作为value,就可以作为set集合来用了var mp = make(map[string]struct{})_, ok := mp["test"]fmt.Println(ok)
}func mapMap() {mp := make(map[string]map[string]string)//date:=mp["test"]//date["test"]="test" panic//make初始化的时候只会初始化第一层的map,而第二层的map是不会初始化的//一定要对第二层的map进行初始化mp["test"] = make(map[string]string)makeDate := mp["test"]makeDate["test"] = "test"fmt.Println(mp)
}