Golang学习记录11——映射(map)

映射的引入map[keytype]valuetype

  1. 映射(map),Go语言中内置的一种类型,它将键值相关联,我们可以通过键key来获取对应的值value。类似其它语言的集合 键值对:一对匹配的信息
  2. 基本语法var 変量名 map[keytype]valuetype
    PS:key、value的类型:boo、数字、string、指针、channel、还可以是只包含前面几个类型的接口、结构体、数组
    PS:key通常为int、string类型,value通常为数字(整数、浮点数)、string、map、结构体
    PS: slice,map,function不可以当作key
package main

import "fmt"

func main()  {
	var m map[int]string    //只声明map,内存没有分配空间

	//必须通过make函数进行初始化,分配空间
	m = make(map[int]string, 5)

	//将键值对存入map
	m[100] = "张三"
	m[102] = "张五"
	m[101] = "张四"
	m[103] = "张六"

	//输出map
	fmt.Println(m)
}
map[100:张三 101:张四 102:张五 103:张六]

PS

  • map集合在使用前一定要make分配空间
  • map的key-value是无序的(不是按照输入顺序)
  • key的值不能重复,索引按照key进行索引,重复会替换value,value可以重复

map的创建方式

  1. 方式1:先声明再分配空间,然后赋键值
  2. 方式2:类型推断,直接分配空间,可不指定长度,然后赋键值
  3. 方式3:直接将具体map赋值给变量,进行类型推断
package main
import "fmt"

func main(){
	//方式1:先声明再分配
	var map1 map[int]string
	map1 = make(map[int]string, 10)
	map1[1] = "jack"
	map1[2] = "helen"
	fmt.Println(map1)

	//方式2:类型推断,不指定长度
	map2 := make(map[int]string)  //不分配长度
	map2[1] = "jack"
	map2[2] = "helen"
	fmt.Println(map2)

	//方式3:直接赋值,将具体map赋值给变量,进行类型推断
	map3 := map[int]string{1:"jack",2:"helen"}
	fmt.Println(map3)
}
map[1:jack 2:helen]
map[1:jack 2:helen]
map[1:jack 2:helen]

对map的操作

  1. 增加和更新操作:通过键进行增加或者更新,如果存在则为更新,不存在则为增加
//map初始化
	map1 := map[int]string{1:"Jack",2:"Helen"}
	fmt.Printf("原始map:%v\n",map1)

	fmt.Println("-------------------map增加/修改-------------------")
	//map增加
	map1[3] = "Mike"
	fmt.Printf("增加元素map:%v\n",map1)
	//更新map
	map1[1] = "Neo"
	fmt.Printf("修改键为1元素map:%v\n",map1)
	//正常使用键进行增加和删除,键存在则为修改,不存在则为添加
原始map:map[1:Jack 2:Helen]
-------------------map增加/修改-------------------
增加元素map:map[1:Jack 2:Helen 3:Mike]
修改键为1元素map:map[1:Neo 2:Helen 3:Mike]
  1. 删除键值对,通过delete()函数——专门用来删除map
    请添加图片描述
	fmt.Println("-------------------map删除-------------------")
	fmt.Printf("删除前map:%v\n",map1)
	delete(map1,2)    //通过键删除,不存在,则不删
	fmt.Printf("删除键为2元素map:%v\n",map1)
	delete(map1,8)    //不存在,则不删
	fmt.Printf("删除键为8元素map:%v\n",map1)
-------------------map删除-------------------
删除前map:map[1:Neo 2:Helen 3:Mike]
删除键为2元素map:map[1:Neo 3:Mike]
删除键为8元素map:map[1:Neo 3:Mike]
  1. map清空
    • 使用遍历删除逐个清空
    • 使用make函数,建立新的空间,原始map丢弃回收
fmt.Println("-------------------map清空-------------------")

	//方式1:遍历删除
	map2 := map[int]string{1:"Jack",2:"Helen"}
	fmt.Printf("清空前map:%v\n",map2)
	for key,_ := range map2{
		delete(map2,key)
	}
	fmt.Printf("清空后map:%v\n",map2)

	//方式2:重置变量空间,使原空间为垃圾,被gc回收
	map3 := map[int]string{1:"Jack",2:"Helen"}
	fmt.Printf("清空前map:%v\n",map3)
	map3 = make(map[int]string)
	fmt.Printf("清空后map:%v\n",map3)
-------------------map清空-------------------
清空前map:map[1:Jack 2:Helen]
清空后map:map[]
清空前map:map[1:Jack 2:Helen]
清空后map:map[]
  1. map查找:通过键进行查找map[键],返回两个参数:value,bool
	fmt.Println("-------------------map查找-------------------")
	fmt.Printf("初始map:%v\n",map1)
	value, flag := map1[1]
	fmt.Printf("是否存在键:%v\t其对应的值为:%v\n",flag,value)
	value, flag = map1[2]
	fmt.Printf("是否存在键:%v\t其对应的值为:%v\n",flag,value)
-------------------map查找-------------------
初始map:map[1:Neo 3:Mike]
是否存在键:true        其对应的值为:Neo
是否存在键:false       其对应的值为:
  1. map长度——len()
mt.Println("-------------------map长度-------------------")
	fmt.Printf("初始map:%v\n",map1)
	fmt.Printf("map的长度为:%v\n",len(map1))
-------------------map长度-------------------
初始map:map[1:Neo 3:Mike]
map的长度为:2
  1. map遍历:通常来说只能使用for-range遍历
fmt.Println("-------------------map遍历-------------------")
	//map遍历正常来说只能使用for-range
	fmt.Printf("初始map:%v\n",map1)
	for k,v := range map1{
		fmt.Printf("map的元素键值为:%v-%v\t\t",k,v)
	}
-------------------map遍历-------------------
初始map:map[1:Neo 3:Mike]
map的元素键值为:1-Neo          map的元素键值为:3-Mike
  1. 二维map:map[key1 type] map[key2type]valuetype
    {key1_1:{key2_1:value,key2_2:value},key2_1:{key2_1:value,key2_2:value}}
fmt.Println("\n-------------------二维map-------------------")
	map_2D := make(map[string]map[int]string) //map分配空间

	map_2D["class1"] = make(map[int]string,3)   //内部map分配空间
	//赋值
	map_2D["class1"][101] = "Jack" 
	map_2D["class1"][102] = "Mike" 

	map_2D["class2"] = make(map[int]string,3)   //内部map分配空间
	//赋值
	map_2D["class2"][101] = "Helen" 
	map_2D["class2"][103] = "Lily"
	fmt.Println(map_2D)

	for k,v := range map_2D{
		for key, value := range v{
			fmt.Printf("%v-%v-%v\t",k,key,value)
		}
	}

	//直接赋值
	map2D := map[string]map[int]string{"class1":{1:"mike",2:"lily"},"class3":{2:"k"}}
	fmt.Println()
	fmt.Println(map2D)
-------------------二维map-------------------
map[class1:map[101:Jack 102:Mike] class2:map[101:Helen 103:Lily]]
class1-101-Jack class1-102-Mike class2-101-Helen        class2-103-Lily
map[class1:map[1:mike 2:lily] class3:map[2:k]]

PS:索引——map[][];
map存储:map{key1:map{k1:v1,k2:v2},key2:map{k3:v3,k4:v4}}

### Golang 中 `map` 的内部实现原理 #### 哈希表作为底层数据结构 Golang中的`map`用于存储键值对,其底层采用了哈希表来高效管理这些成对存在的元素[^1]。 #### 解决哈希冲突的方式——拉链法 当遇到不同的键映射到了相同的索引位置时,即发生哈希碰撞的情况下,Go语言采取了拉链法这一策略来进行处理。具体而言,在同一个桶(bucket)里形成一个单向链表,从而使得即使存在多个具有相同哈希值的项也能被妥善保存下来。 #### 数据结构描述 表示`map`的核心结构体名为`hmap`,它不仅包含了当前已存入条目的总数(`count`),还记录着一些辅助性的元数据字段,比如标志位(`flags`)、桶数组长度的二进制对数值(`log_2 B`)以及溢出桶的数量估计(`noverflow`)等。此外,为了支持高效的查找操作,该结构体内也维护了一个指向实际存储区域(称为buckets)的指针成员变量(`buckets`);而当涉及到扩容过程时,则会有另一个备用空间(oldbuckets),用来暂时存放旧版本的数据副本直至迁移工作全部完成为止[^4]。 #### 安全特性说明 值得注意的是,尽管`map`提供了便捷的操作接口供开发者使用,但它本身并不具备任何同步保护措施,因此在同一时间点上由不同goroutine并发执行针对同一张表格内的读取或修改动作将会引发程序崩溃(Panic)[^3]。 #### 删除操作的具体流程 对于删除指定key-value的过程来说,Go运行库提供了一套专门负责清理工作的函数—`mapdelete()`。此方法接收三个参数:类型信息(`t *maptype`)、待作用的目标对象句柄(`h *hmap`)还有代表要移除的那个特定实体的关键字(`key unsafe.Pointer`),进而依据给定条件定位目标节点并将其从容器中摘除出去[^2]。 ```go func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { // 实现细节... } ``` #### 更新操作的逻辑概览 在进行更新操作时,系统会先尝试按照既定算法计算出对应于输入关键字的散列编码(topHash),随后以此为基础进入相应的bucket单元格展开逐级检索活动。一旦发现匹配的对象实例之后便立即启动内存复制指令(typedmemmove())把新传入的内容覆盖上去,并随即终止后续遍历行为以节省资源消耗[^5]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值