golang语言map的并发和排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang语言map的并发和排序相关的知识,希望对你有一定的参考价值。

参考技术A golang语言map的并发和排序

golang缺省的map不是thread safe的,如果存在读写并发的使用场景,必须在外面使用lock机制。
包sync里面引入一个安全map;

用法:

运行结果如下:

golang官方说法map并不排序,不按key排序,也不按插入顺序排序,也就是说map是无序的,无法保证任何排序。
下面是一种常见的给map排序输出的办法:

Golang:map的定义操作排序以及map切片

map概述

golang中的引用类型

与其他语言中的map类型基本相似,都是k-v形式的,k不可重复,元素是无序的,并且支持扩容

基本语法

var 变量名 map[keytype]valuetype

key可以是很多类型

bool、数字、string、指针、channel,还可以是只包含前面几种类型的 接口、结构体、数组

但是!!!slice、map、function是不可以作为map的key,因为无法使用 == 判断key是否相等

value的类型就没有特别的要求

声明

map的声明是不会分配内存的,初始化需要make,分配内存后才能赋值和使用。

map的声明示例

package main

import "fmt"

//声明一个map变量
var map1 map[string]string

func main() 
	//第一种方式:先声明,再make
	fmt.Printf("map1=%v\\n", map1)
	fmt.Printf("map1 address=%p\\n", &map1)     //变量map1是有内存地址的
	fmt.Printf("map1==nil? %v\\n", map1 == nil) //在没有make之前map1==nil为true成立,代表没有分配内存空间
	//使用map要先make
	map1 = make(map[string]string, 2) //分配了2个空间
	map1["LeoLee"] = "18"
	fmt.Printf("map1=%v, length=%d\\n", map1, len(map1))
	map1["Lydia"] = "18"
	fmt.Printf("map1=%v, length=%d\\n", map1, len(map1))
	map1["LeoLee"] = "26"
	fmt.Printf("map1=%v, length=%d\\n", map1, len(map1))
	map1["Tony"] = "1" //map会自动扩容
	fmt.Printf("map1=%v, length=%d\\n", map1, len(map1))

	//第二种方式:声明map变量的同时,make
	map2 := make(map[string]int) //这里不定义初始size,根据内置函数make的api说明,会分配一个默认起始大小:0
	fmt.Printf("map2=%v, length=%d\\n", map2, len(map2))
	map2["a"] = 1
	map2["b"] = 2
	fmt.Printf("map2=%v, length=%d\\n", map2, len(map2))

	//第三种方式:声明直接赋值
	map3 := map[int]string
		1: "c",
		2: "d",
	
	fmt.Printf("map3=%v, length=%d\\n", map3, len(map3))

操作map

map的增删改查、以及循环遍历(map只能使用for range遍历):

package main

import "fmt"

func main() 
	//map删除元素,使用内置函数delete
	map1 := map[string]string
		"a": "欸",
		"b": "币",
		"c": "西",
	
	delete(map1, "a") // 若map为nil或无此元素,delete不进行操作
	delete(map1, "d")
	fmt.Printf("map1=%v, length=%d\\n", map1, len(map1))
	//golang的map没有办法一次性删除所有的key-value,需要遍历删除
	for k, _ := range map1 
		delete(map1, k)
	
	fmt.Printf("map1=%v, length=%d\\n", map1, len(map1))
	//或者对该map变量重新进行make初始化(指向新的内存地址),让该map变量对应的原来的引用对象成为垃圾。
	map1 = make(map[string]string)
	fmt.Printf("map1=%v, length=%d\\n", map1, len(map1))

	//获取对应key的value
	map2 := map[string]string
		"a": "欸",
		"b": "币",
		"c": "西",
	
	val1, getRes1 := map2["a"]
	fmt.Printf("key:a, value:%s, getRes1:%v\\n", val1, getRes1)
	val2, getRes2 := map2["d"]
	fmt.Printf("key:d, value:%s, getRes2:%v\\n", val2, getRes2)

	//遍历,map的遍历只能使用for range方式
	for k, v := range map2 
		fmt.Println(k, v)
	

map切片

map切片类似于Java中的List<Map>或者是Array<Map>

package main

import "fmt"

//map切片,类似于Java中List<Map>
func main() 
	personSlice := make([]map[string]string, 2, 2)
	personSlice[0] = make(map[string]string)
	personSlice[0]["name"] = "LeoLee"
	personSlice[0]["age"] = "26"
	personSlice[1] = make(map[string]string)
	personSlice[1]["name"] = "Lydia"
	personSlice[1]["age"] = "29"
	//如果继续追加,会有越界
	/*personSlice[2] = make(map[string]string)
	personSlice[2]["name"] = "Lydia"
	personSlice[2]["age"] = "29"*/
	//所以需要使用slice的append,这样切片可以动态扩容
	personMap1 := make(map[string]string)
	personMap1["name"] = "Tony"
	personMap1["age"] = "30"
	personSlice = append(personSlice, personMap1)
	for _, m := range personSlice 
		fmt.Println(m)
	

map的排序

由于Golang中没有提供原生的有序map,所以Golang中的有序map需要开发者自己实现,以下是一个对map进行有序输出的小例子:

package main

import (
	"fmt"
	"sort"
)

//map排序
func main() 
	//在老版本中,使用print输出map也会是无序的,新版本中变为升序
	//但是遍历map仍然是无序的
	map1 := map[int]string
		3: "b",
		2: "a",
		6: "c",
		5: "e",
	
	fmt.Println("map1=", map1)
	for k, v := range map1 
		fmt.Printf("%d:%s\\n", k, v)
	
	map2 := make(map[string]string)
	map2["b"] = "1"
	map2["a"] = "4"
	map2["g"] = "2"
	map2["f"] = "8"
	fmt.Println("map2=", map2)
	for k, v := range map2 
		fmt.Printf("%s:%s\\n", k, v)
	

	//对map进行排序
	/*1.先将map的key放入切片中
	2.对切片进行排序
	3.遍历切片,按照切片遍历的顺序获取key对应的value*/
	var keys1 []int
	for k, _ := range map1 
		keys1 = append(keys1, k)
	
	fmt.Printf("keys1=%v\\n", keys1)
	//使用sort包下的Ints函数,Ints函数将会把传入的int类型切片按照递增顺序排序
	sort.Ints(keys1)
	fmt.Printf("keys1=%v\\n", keys1)
	for _, key := range keys1 
		val, _ := map1[key]
		fmt.Println(key, ":", val)
	

以上是关于golang语言map的并发和排序的主要内容,如果未能解决你的问题,请参考以下文章

Golang中sync.Map的实现原理

Golang 并发读写map安全问题详解

Golang:map的定义操作排序以及map切片

Golang:map的定义操作排序以及map切片

Golang:map的定义操作排序以及map切片

Golang:map的定义操作排序以及map切片