前言
Go语言中提供了映射关系容器为map
,类似Python中的字典。其内部使用散列表(hash)
实现、无序、为引用数据类型。
不同于Python字典之处是map的key可以为数字,在声明map时就需要指定 map中key和value的数据类型。
为什么很多语言中都有类似map这种键值对数据集合呢?因为这种数据类型最大的特点就是查找速度快。
为什么map的查询速度会特别快呢?
map之所以查询速度快是因为,它可以根据key直接找到数据存储的位置,而其他数据类型查时从前往后遍历会比较耗时。就是利用hash存储。
以上只是hash存储的基本存储模型,其他编程语言的键值对集合大多基于此基础进行优化。
map数据类型有以下3大特点:
键不能重复
键必须是可hash的(int、bool、float、srting、arry),arry中包含了不可hash元素也不可以!
键在map集合中是无序的
map声明
map的key可以是int、bool、float、srting、arry但是arry中不能出嵌套lice元素。
package main import "fmt" func main() { //1.创建map的方式 //1.声明+初始化 userInfo := map[string]string{"name": "Martin", "age": "18", "e-mail": "13220198866@163.com"} fmt.Println(userInfo) userList := []map[string]string{map[string]string{"name": "Martin", "age": "18", "e-mail": "martin@163.com"}, map[string]string{"name": "Alex", "age": "70", "e-mail": "Alex@163.com"}} userList = append(userList, map[string]string{"name": "zhangdaqian", "age": "188", "e-mail": "zhangdaqian@163.com"}) fmt.Println(userList) //2.make方式 m1 := make(map[int]int, 10) m1[0] = 0 m1[1] = 1 fmt.Println(m1) //2.声明map用于整体赋值 var m2 map[int]int //m2["age"]=19 无法设置值 指向nil m2=m1 fmt.Println(m2) //3.new用于整体赋值 m3:=new(map[int]int) m3=&m2 fmt.Println(m3) //返回的是指针 //4.声明数组类型的map m4:=map[[1]int]int{[1]int{1}:1,[1]int{2}:2} m4[[1]int{3}]=3 m4[[1]int{4}]=4 fmt.Println(m4) /* { [1]:1, [2]:2, [3]:3, [4]:4 } */ for k, v := range m4 { fmt.Println(k,v) } }
map的定义及基本操作
package main import "fmt" func main() { //定义了1个map变量,key是sring类型、value是int类型 var m1 map [string]int fmt.Println(m1 == nil) //还没有初始化(没有在内存中开辟空间) //初始化:估算好map的容量,避免程序运行期间在扩容 m1 = make( map [string]int, 10) m1[ "年龄" ] = 18 fmt.Println(m1) fmt.Println(m1[ "年龄" ]) //获取不存在的key v, ok := m1[ "姓名" ] if !ok { fmt.Println( "没有该key" ) } else { fmt.Println(v) } //直接获取不存在的key,返回对应类型的默认值 fmt.Println(m1[ "不存在的key" ]) //遍历map的key和value m2 := make( map [string]string, 10) m2[ "姓名" ] = "Martin" m2[ "性别" ] = "男" for k, v := range m2 { fmt.Println(k, v) } //仅遍历map的keys for k := range m2 { fmt.Println(k) } //仅遍历map的values for _, v := range m2 { fmt.Println(v) } //删除map中的key delete(m2, "姓名" ) fmt.Println(m2) //删除map中不存在的key() no-option delete(m1, "不存在的key" ) /* go doc builtin.delete 查看内置函数的用法 func delete(m map[Type]Type1, key Type) The delete built-in function deletes the element with the specified key (m[key]) from the map. If m is nil or there is no such element, delete is a no-op. */ } |
嵌套map
package main import "fmt" func main() { m1:=make(map[string]string) m1["name"]="Martin" m2:=make(map[bool]int) m2[true]=1 m3:=make(map[[2]int][2]string) m3[[2]int{1,2}]=[2]string{"a","b"} m4:=make(map[string]map[string]string) //{"wife":{"name":"Elizabeth","gender":"Female"} } m4["wife"]= map[string]string{"name":"Elizabeth","gender":"Female"} m4["husband"]= map[string]string{"name":"George","gender":"Male"} m5:=map[string][]int{"n1":[]int{1,3,4},"n2":[]int{2,4,6}} fmt.Println(m1,m2,m3,m4,m5) //[{},{},{}] var a1=make([]map[string]string,1,20) a1[0]=map[string]string{"name":"eric","gender":"Female","detail":"我是eric我喜欢..."} a1=append(a1,map[string]string{"name":"egon","gender":"male","detail":"我是egom我喜欢..."}) fmt.Println(len(a1)) fmt.Println(a1) //map里面嵌套map v6 := make(map[string]map[int]int) v6["n1"] = map[int]int{1: 99, 2: 666} v6["n2"] = map[int]int{2: 33, 4: 444} fmt.Println(v6) v7 := make(map[string][2]map[string]string) v7["group1"] = [2]map[string]string{map[string]string{"name": "Alex", "age": "18"}, map[string]string{"name": "eric", "age": "34"}} v7["group2"] = [2]map[string]string{map[string]string{"name": "Tony", "age": "28"}, map[string]string{"name": "Bob", "age": "23"}} fmt.Println(v7) /* map[group1:[map[age:18 name:Alex] map[age:34 name:eric]] group2:[map[age:28 name:Tony] map[age:23 name:Bob]]] { group1:[ {"name":"Alex","age":"18"}, {"name":"eric","age":"34"} ] group2:[ {"name":"Tony","age":"28"}, {"name":"Bob","age":"23"} ] } */ }
排序显示map
无论是Python的字典还是Go中的map,它们都是无序的。那么我们如何对map进行排序呢?就需要1些迂回的方法;
对map的key进行排序做成切片,然后遍历切片中的key逐一获取map中的元素。
package main import ( "fmt" "math/rand" //math包中有个rand模块 "sort" "time" ) func main() { //获取当前时间的 纳秒(随机数字) rand.Seed(time.Now().UnixNano()) //声明1个map存放{stud纳秒:分数 } var scoreMap = make( map [string]int, 200) for i := 0; i < 100; i++ { key := fmt.Sprintf( "stud%2d" , i) value := rand.Intn(100) //生成0-99的随机整数(作为分数) scoreMap[key] = value } var keys = make([]string, 0, 200) for key := range scoreMap { keys = append(keys, key) } //安装字符串进行排序 sort.Strings(keys) //通过排序后的key,对map逐一获取值 for _, key := range keys { fmt.Println(scoreMap[key]) } } |
切片和map组合数据类型
如何在go里面组织这种多维度的数据类型?
1.make创造1个元素为map的切片
[{"key1":"v1"},{"key2":"v2"}]
创造1个切片[],内部的元素=map[int]string
2.make创造 值(value)为map的切片
{"ke1":["v1","v2","v3"] }
创造 1个map key为 [string] 值为[]string
package main import ( "fmt" ) //map和slice组合 func main() { //1.创造1个切片[],内部的元素=map[int]string var s1 = make([] map [int]string, 10, 10) //注意需要对 内部的map也进行初始化 s1[0] = make( map [int]string, 1) s1[0][10] = "北京" fmt.Println(s1) //2.创造1个map var m2 = make( map [string][]string, 10) //对map中的切片进行初始化 m2[ "北京市" ] = []string{ "朝阳区" , "海淀区" , "昌平区" } fmt.Println(m2) } |
总结
目前主要学到了,Go中的数据类型(string、int、bool、pointer、arry、slice、map)以及怎么定义该数据类型的变量,以便于在使用Go的情况下,存放不同数据模型的数据。
ackage main import "fmt" func main() { //声明1个字符串变量 var name string fmt.Println(name) //声明1个数组变量 var a1 [3]int fmt.Println(a1) //声明完了就有默认值 //声明1个切片类型的变量 var s1 []int fmt.Println(s1 == nil) //声明二维数组 var a3 [3][3]int //对二维数组进行初始化 a3 = [3][3]int{ [3]int{1, 2, 3}, [3]int{4, 5, 6}, [3]int{7, 8, 8}, } fmt.Println(a3) // a4 := [3]int{1, 2, 3} a5 := modifyArry(a4) fmt.Println(a4) fmt.Println(a5) s2 := []string{ "北京" , "海淀" , "五道口" } s3 := modifySlice(s2) fmt.Println(s2) fmt.Println(s3) //map数据类型 var m1 map [string]int //注意使用make函数对map进行初始化 m1 = make( map [string]int, 10) //直接使用map m2:=make( map [string]int) m2[ "name" ]=12 fmt.Println(m1,m2) } //数组是值类型:修改数组时,会复制 1个新的数组让我们修改 func modifyArry(a1 [3]int) (ret [3]int) { a1[0] = 100 return a1 } //切片是引用类型:修改切片时,不会复制1个新的切片让我们修改(修改原来的) func modifySlice(s2 []string) (ret2 []string) { s2[0] = "河北省" return s2 } |
练习
// // //遍历数组 // package main // import ( // "fmt" // ) // func main() { // //根据索引访问元素 // var cities = [...]string{"北京", "上海", "深圳"} // for i := 0; i < len(cities); i++ { // fmt.Printf("%s\n", cities[i]) // } // //遍历数组 // for i, v := range cities { // fmt.Println(i, v) // } // } // package main // import ( // "fmt" // ) // func main() { // //arry数值类型辩证 // a1 := [...]string{"河北", "河南", "山东"} // a2 := a1 // a1[len(a1)-1] = "山西" // fmt.Println(a1) //[河北 河南 山西] // fmt.Println(a2) //[河北 河南 山东] // } //练习题目 // package main // import ( // "fmt" // ) // func main() { // //1.求数组[1, 3, 5, 7, 8]所有元素的和 // arr1 := [...]int{1, 3, 5, 7, 8} // var sum int // for _, v := range arr1 { // sum += v // } // fmt.Println(sum) // /*找出数组中和为指定值的两个元素的下标,比如从数组[1, 3, 5, 7, 8]中找出和为8的两个元素的下标分别为(0,3)和(1,2)*/ // for i := 0; i < len(arr1); i++ { // for j := i + 1; j < len(arr1); j++ { // if arr1[i]+arr1[j] == 8 { // fmt.Printf("%d %d\n", i, j) // } // } // } // } // package main // import "fmt" // func main() { // //声明1个字符串变量 // var name string // fmt.Println(name) // //声明1个数组变量 // var a1 [3]int // fmt.Println(a1) //声明完了就有默认值 // //声明1个切片类型的变量 // var s1 []int // fmt.Println(s1 == nil) // //声明二维数组 // var a3 [3][3]int // //对二维数组进行初始化 // a3 = [3][3]int{ // [3]int{1, 2, 3}, // [3]int{4, 5, 6}, // [3]int{7, 8, 8}, // } // fmt.Println(a3) // // // a4 := [3]int{1, 2, 3} // a5 := modifyArry(a4) // fmt.Println(a4) // fmt.Println(a5) // s2 := []string{"河北", "保定", "唐县"} // s3 := modifySlice(s2) // fmt.Println(s2) // fmt.Println(s3) // //map数据类型 // var m1 map[string]int // //注意使用make函数对map进行初始化 // m1 = make(map[string]int, 10) // //直接使用map // m2:=make(map[string]int) // m2["name"]=12 // fmt.Println(m1,m2) // } // //数组是值类型:修改数组时,会复制 1个新的数组让我们修改 // func modifyArry(a1 [3]int) (ret [3]int) { // a1[0] = 100 // return a1 // } // //切片是引用类型:修改切片时,不会复制1个新的切片让我们修改(修改原来的) // func modifySlice(s2 []string) (ret2 []string) { // s2[0] = "河北省" // return s2 // } package main import ( "fmt" "strings" "unicode" ) func main() { var ChineseCount int s1 := "hello你好少年" for _, c := range s1 { //1.判断字符是否为汉字(rune类型) if unicode.Is(unicode.Han, c) { ChineseCount++ } } fmt.Printf( "汉字的数量为:%d\n" , ChineseCount) //2.判断句子中单词出现的次数(word count) word := "how do you do" //英文句子中单词以空格隔开 WordArry := strings.Split(word, " " ) wordCountMap := make( map [string]int) for _, v := range WordArry { _, ok := wordCountMap[v] if ok { wordCountMap[v]++ } else { wordCountMap[v] = 1 } } fmt.Println(wordCountMap) //3.判断句子是否为以下回文句型 /* 上海自来水来自海上 山西运煤车煤运西山 */ LoopSting := "山西运煤车煤运西山" //定义1个存放rune字符串(汉字)的切片 RuneSlice := make([]rune, 0, len(LoopSting)) for _, c := range LoopSting { RuneSlice = append(RuneSlice, c) } for i := 0; i < len(RuneSlice)/2; i++ { if RuneSlice[i] != RuneSlice[len(RuneSlice)-i-1] { fmt.Println( "不是回文句型" ) return //在main函数中 return 程序结束 } } fmt.Println( "是回文句型" ) } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
2019-03-29 CloudStack 云计算平台框架
2017-03-29 Python购物车