网站域名多少钱一年,河南洛阳网站建设,做酒水网站有哪些,C wordpress 分类Map
Go语言中提供的映射关系容器为map#xff0c;其内部使用散列表#xff08;hash#xff09;实现
map是一种无序的基于key-value的数据结构#xff0c;Go语言中的map是引用类型#xff0c;必须初始化才能使用。
它提供了高效的查找、插入和删除操作#xff0c;非常适…Map
Go语言中提供的映射关系容器为map其内部使用散列表hash实现
map是一种无序的基于key-value的数据结构Go语言中的map是引用类型必须初始化才能使用。
它提供了高效的查找、插入和删除操作非常适合用于构建关联数组或字典。
Map 的基本概念
每个 map 都是一个无序的集合通过键来唯一标识值。 键可以是任何可以比较的类型如字符串、整数、结构体等而值可以是任何类型。 map 是引用类型因此在传递给函数时函数接收到的是指向同一底层数据结构的引用。
Go 中的 map 实现细节
Go 的 map 是基于哈希表实现的具有高效的查找、插入和删除性能。
底层实现使用桶来存储多个键值对并通过链表解决哈希冲突问题。
map 具有自动扩容的特性以保持性能和存储效率。
哈希函数每个键在插入时会被传入一个哈希函数该函数会生成一个哈希值。这个哈希值用于确定在底层数组中的位置。
Go 使用的是非加密的哈希函数针对不同类型如字符串、整数等具有不同的哈希算法。桶Bucket在 Go 的 map 中底层数组被称为桶bucket。每个桶可以存储多个键值对这解决了哈希冲突的问题。
当两个或多个键经过哈希运算后映射到同一个桶时Go 会使用链表的方式将它们链接在该桶中。
每个桶的大小和数量会根据存储的键值对数量而动态扩展。扩容当 map 中的元素数量超过一定阈值时Go 会对 map 进行扩容。
扩容时Go 将创建一个新的、更大的底层数组并重新计算每个键的哈希值以确定新的位置
然后将现有的键值对复制到新的桶中。
这种扩容策略旨在保持哈希表操作的效率同时降低碰撞的概率。负载因子负载因子是一个衡量哈希表是否需要扩展的指标通常表示为元素数量与桶的数量之比。
在 Go 中当负载因子超过某个阈值时会触发扩容。创建 Map
可以使用 make 函数或字面量来创建 map。
package mainimport fmtfunc main() {// 创建一个空的 map键为字符串值为整数ageMap : make(map[string]int)// 插入键值对ageMap[Alice] 25ageMap[Bob] 30fmt.Println(年龄Map:, ageMap) // 输出: 年龄Map: map[Alice:25 Bob:30]
}
package mainimport fmtfunc main() {// 使用字面量创建 mapfruits : map[string]int{苹果: 10,香蕉: 20,橙子: 15,}fmt.Println(水果数量:, fruits) // 输出: 水果数量: map[香蕉:20 橙子:15 苹果:10]
}
访问和修改 Map
使用键来访问或修改对应的值。
package mainimport fmtfunc main() {fruits : map[string]int{苹果: 10,香蕉: 20,}// 访问值appleCount : fruits[苹果]fmt.Println(苹果的数量:, appleCount) // 输出: 苹果的数量: 10// 修改值fruits[苹果] 12fmt.Println(更新后的苹果数量:, fruits[苹果]) // 输出: 更新后的苹果数量: 12// 检查某个键是否存在if count, exists : fruits[橙子]; exists {fmt.Println(橙子的数量:, count)} else {fmt.Println(橙子不存在)}
}
判断键是否存在
Go语言中有个判断map中键是否存在的特殊写法格式如下
value, ok : map[key]
func main() {scoreMap : make(map[string]int)scoreMap[张三] 90scoreMap[小明] 100// 如果key存在ok为true,v为对应的值不存在ok为false,v为值类型的零值v, ok : scoreMap[张三]if ok {fmt.Println(v)} else {fmt.Println(查无此人)}
}删除 Map 中的元素
可以使用 delete 函数删除某个键及其对应的值。
使用delete()内建函数从map中删除一组键值对delete()函数的格式如下
delete(map, key)
- map:表示要删除键值对的map
- key:表示要删除的键值对的键如果删除的键不存在则delete()函数不会报错。
package mainimport fmtfunc main() {fruits : map[string]int{苹果: 10,香蕉: 20,}// 删除香蕉delete(fruits, 香蕉)fmt.Println(删除后的水果数量:, fruits) // 输出: 删除后的水果数量: map[苹果:10]
}
遍历 Map
可以使用 for range 循环遍历 map 的所有键值对。
遍历map时的元素顺序与添加键值对的顺序无关。
package mainimport fmtfunc main() {fruits : map[string]int{苹果: 10,香蕉: 20,橙子: 15,}// 遍历 mapfor fruit, count : range fruits {fmt.Printf(%s 的数量是: %d\n, fruit, count)}
}//只遍历key
for key : range fruits {fmt.Println(key)
}//只遍历value
for _, value : range fruits {fmt.Println(value)
}按照指定顺序遍历map 将 map 中的键提取到切片中。对切片进行排序。按照排序后的键顺序遍历 map。 逻辑步骤概述
提取键我们使用 for key : range fruits 迭代 map 的键并将这些键添加到切片 keys 中。
排序使用 sort.Strings(keys) 对键进行排序。根据具体的键类型如 int、string、float 等可以使用适当的排序函数。
遍历最后我们遍历排序后的切片并使用它来访问 map 中的值按照特定顺序输出结果。
package mainimport (fmtsort
)func main() {// 创建一个 mapfruits : map[string]int{香蕉: 20,苹果: 10,橙子: 15,草莓: 25,}// 1. 提取键到切片keys : make([]string, 0, len(fruits))for key : range fruits {keys append(keys, key)}// 2. 对切片进行排序sort.Strings(keys)//调用sort.Strings()函数对切片进行排序,默认升序排序// 3. 按照排序后的键顺序遍历 mapfor _, key : range keys {fmt.Printf(%s 的数量是: %d\n, key, fruits[key])}
}苹果 的数量是: 10
香蕉 的数量是: 20
草莓 的数量是: 25
橙子 的数量是: 15
元素为map类型的切片
在 Go 语言中切片的元素可以是任意类型包括 map 类型。这种灵活性使得可以轻松地组织和管理复杂的数据结构。
当需要存储一组具有相同特征的物体时可以使用 map 来表示每个物体的属性然后将这些 map 存储在切片中。
逻辑步骤概述
创建切片我们定义了一个切片 studentGrades其元素类型为 map[string]int用来存储学生的姓名和成绩。添加元素使用 append() 函数将新的 map 添加到切片中每个 map 存储一个学生的成绩。遍历切片通过两层 for 循环遍历切片中的每个 map并输出学生的姓名和成绩。
package mainimport fmtfunc main() {// 创建一个切片元素类型为 map[string]intvar studentGrades []map[string]int// 添加学生的成绩到切片中studentGrades append(studentGrades, map[string]int{Alice: 85,Bob: 90,})studentGrades append(studentGrades, map[string]int{Charlie: 70,David: 95,})// 遍历切片中的 mapfor i, grades : range studentGrades {fmt.Printf(学生 %d 的成绩:\n, i1)for name, grade : range grades {fmt.Printf( %s: %d\n, name, grade)}}
}学生 1 的成绩:Alice: 85Bob: 90
学生 2 的成绩:Charlie: 70David: 95
可以根据需要使用不同类型的 map例如map[string]string用于存储键为字符串值也为字符串的映射关系如存储用户信息或配置项。嵌套结构可以将更复杂的结构体作为值。type Student struct {Name stringGrade int
}var students []map[string]Studentstudents append(students, map[string]Student{Alice: {Name: Alice, Grade: 85},Bob: {Name: Bob, Grade: 90},})
值为切片类型的map
在 Go 语言中您可以创建一个 map其值类型为切片slice。
这种数据结构非常适用于需要将多个值与某个键关联的场景
在 Go 语言中使用值为切片类型的 map 允许您轻松管理多个值与对应键的关系。
这种灵活性使得可以满足复杂的数据结构需求便捷地组织和访问数据。
在实际开发中可用于各种场景例如学生管理、产品信息处理等。
比如将多个学生的成绩与他们的名字关联或是将多个订单的项目与一个用户关联。 逻辑步骤概述
创建 map初始化一个 map键为 string值为 []int整型切片。添加数据向 map 中添加键值对其中值是一个切片存储多个成绩。遍历 map通过 for range 遍历 map并对每个键值的切片进行进一步遍历输出学生的姓名及其成绩。更新成绩使用 append() 函数向某个学生的成绩切片中添加新的成绩实现动态更新。
package mainimport fmtfunc main() {// 创建一个 map键为字符串值为整数切片scores : make(map[string][]int)// 向 map 中添加数据scores[Alice] []int{85, 90, 92}scores[Bob] []int{78, 82}scores[Charlie] []int{88, 91, 85}// 遍历 mapfor name, scoreList : range scores {fmt.Printf(%s 的成绩: , name)for _, score : range scoreList {fmt.Printf(%d , score)}fmt.Println() // 换行}// 示例给某个学生添加一个成绩scores[Alice] append(scores[Alice], 95)fmt.Printf(更新后 Alice 的成绩: %v\n, scores[Alice])
}
Alice 的成绩: 85 90 92
Bob 的成绩: 78 82
Charlie 的成绩: 88 91 85
更新后 Alice 的成绩: [85 90 92 95]
其他用法
可以根据需要将值的类型定义为其他类型的切片
如 map[string][]string 用于存储学生的课程列表
或 map[string][]float64 用于存储某个产品的价格历史等。
courses : make(map[string][]string)
courses[Alice] []string{数学, 英语, 科学}
courses[Bob] []string{艺术, 体育}for student, courseList : range courses {fmt.Printf(%s 的课程: %v\n, student, courseList)
}prices : make(map[string][]float64)
prices[苹果] []float64{1.5, 2.0, 2.5}
prices[香蕉] []float64{1.8, 2.2, 2.6}for fruit, priceList : range prices {fmt.Printf(%s 的价格: , fruit)for _, price : range priceList {fmt.Printf(%.2f , price)}fmt.Println() // 换行
}
注意事项
无序性map 的元素顺序是无序的。在遍历时输出的顺序并不一定与插入的顺序相同。
引用类型map 是引用类型传递给函数时传递的是引用因此对 map 的修改会影响到原始数据。
零值如果尝试访问一个不存在的键Go 会返回该值类型的零值。在整型 map 中未存在的键返回 0。
并发安全map 在并发环境下不安全多个 goroutine 同时读写 map 可能会导致程序崩溃。可使用 sync.Mutex 或其他机制来实现并发安全访问。