golang之map入门

简介: golang之map入门
0.如何确定key是否存在? 如果访问了不存在的key会如何?


确定key是否存在,用ok判别式

if _,ok := m[key]; ok {
    print("key存在")
} else {
    print("key不存在")
}

参考:

ok判别式

在Go中操作map, 无论key是否存在,都不会panic或者返回error!

即可以访问不存在的key, 得到的值是对应 value 类型的零值

如下:

package main
import "fmt"
func main() {
  m := make(map[int]int)
  m[0] = 111
  m[1] = 1313
  m[2] = 9876
    fmt.Println(m[4])
  m2 := make(map[string]string)
  fmt.Println(m2["cuishuang"])
  var m3 map[string]string
  fmt.Println(m3["dashen"])
}

输出为:

0
1.key的类型可以是哪些


简言之,可以判断(==)的类型,都可以作为map的键名.

bool, int,float,string, 指针, channel 以及 只包含前面几个类型的 interface,struct, array

而如 slice, map 以及 function 不能作为map的key,因为这几种类型无法用 == 来判断

原文如下:

As mentioned earlier(如前所述), map keys may be of any type that is comparable. The language spec defines this precisely, but in short, comparable types are boolean, numeric, string, pointer, channel, and interface types, and structs or arrays that contain only those types. Notably absent from the list are slices, maps, and functions; these types cannot be compared using ==, and may not be used as map keys.

comparable types, 即可比较类型,可判等类型

即slice,map,function不可比较,包含这三种类型的interface,struct,array也不可比较;除此以外的都可以比较~

关于类型是否能判等,可参考

利用反射,探究Go语言中的数据类型--哪些数据类型可以对比?

map之间能否直接判等? (直接 **map1 == map2** 是错误的)

结构体判等 (invalid operation: d1 == d2 (struct containing map[string]int cannot be compared))

接口的比较性如果接口存储的动态类型值是不可比较的,则运行时会报错

切片的比较切片唯一合法的比较操作是和nil比较




2.map键值互换


o := map[string]int{"a": 0, "b": 0, "c": 2}

如果原map的值不唯一(如上),会导致新map无法完全包含原map的键值对(相同key会被覆盖)。该问题可以采用多值map来解决,即将新map的键值定义为一个切片类型

var (
    o = map[string]int{"a": 0, "b": 0, "c": 2}
)
func main() {
    fmt.Println(o)
    n := map[int][]string{}
    for k, v := range o {
        n[v] = append(n[v], k)
    }
    fmt.Println(n)
}

输出:

map[a:0 b:0 c:2]
map[0:[a b] 2:[c]]
3.可以对map的键值取指针吗?


不可以!

map 中的元素并不是一个变量,而是一个值。 因而不能对 map 的元素进行取址操作(类似于&5,编译不过)

package main
import (
  "fmt"
)
func main() {
  m := make(map[string]int)
  m["age"] = 27
  fmt.Println(&m["age"])
}

报错:

cannot take the address of m["age"]
4.当 map 的键值为结构体类型的值,那么无法直接修改结构体中的字段值


go 中的 map 的 value 本身是不可寻址的,因为 map 的扩容的时候,可能要做 key/val pair迁移

package main
import "fmt"
func main() {
  type person struct {
    name string
    city string
    age  int
  }
  var personMap = make(map[int]person)
  p5 := person{
    name: "史铁生",
    city: "北京",
    age:  20,
  }
  p1 := person{
    "莫言",
    "山东高密",
    30,
  }
  personMap[p5.age] = p5
  personMap[p1.age] = p1
  fmt.Println("map为:", personMap)
  // 修改
  // 常见错误  不能直接修改map 结构体中的值
  //personMap[p1.age].name = "蒲松龄"  // cannot assign to struct field personMap[p1.age].name in map
  // --------正确方式---------
  fmt.Println("-----以下为正确修改方式-----")
  var personMap2 = make(map[int]*person)
  personMap2[p5.age] = &p5
  personMap2[p1.age] = &p1
  fmt.Println(*personMap2[p1.age])
  fmt.Println(*personMap2[p5.age])
  fmt.Println("修改后:")
  personMap2[p1.age].name = "蒲松龄"
  fmt.Println(*personMap2[20])
  fmt.Println(*personMap2[p1.age])
}

输出:

map为: map[20:{史铁生 北京 20} 30:{莫言 山东高密 30}]
-----以下为正确修改方式-----
{莫言 山东高密 30}
{史铁生 北京 20}
修改后:
{史铁生 北京 20}
{蒲松龄 山东高密 30}

golang 修改map 结构体中的值

map增删改查




5.map之间能否直接判等?


不能!

直接 map1 == map2 是错误的

map后面直接用 == 比较,只能用来判断 map 是否为 nil, 即只可以 "m == nil"

可以通过reflect.DeepEqual来"深度比较"两个slice/struct/map 是否相等


参考:

如何比较两个 map 相等

比较两个 slice/struct/map 是否相等




6.实现key有序的map


借助slice就可以

package main
import (
  "fmt"
  "sort"
)
func main() {
  var m = make(map[int]string)
  m[1] = "张三"
  m[2] = "李四"
  m[3] = "王五"
  m[4] = "陈六子"
  fmt.Println()
  fmt.Println("下面迭代时会乱序:")
  fmt.Println()
  /*
    第3位是王五
    第4位是陈六子
    第1位是张三
    第2位是李四
    (且每次执行输出顺序不确定,可能每次都不一样)
  */
  for k, v := range m {
    fmt.Printf("第%d位是%s\n", k, v)
  }
  // 改为顺序输出:
  fmt.Println("---------------顺序输出----------------")
  sli := make([]int, 0)
  for k := range m {
    sli = append(sli, k)
  }
  //sort.Strings(sli)
  sort.Ints(sli)
  for _, val := range sli {
    fmt.Printf("第%d位是%s\n", val, m[val])
  }
  /*
    ---------------顺序输出----------------
    第1位是张三
    第2位是李四
    第3位是王五
    第4位是陈六子
  */
}

深入探究map迭代时的乱序

统计某月有几篇博文




7.map 的并发读写问题


并发读写map可能会报错(不是100%),而且该错误无法通过recover恢复(并发对map读写可能会报fatal error

并发读写slice不会报错(最后的数据可能不对)


更多参考:

golang之map并发访问

目录
相关文章
|
3月前
|
存储 Java
从零开始学习 Java:简单易懂的入门指南之Map集合(二十三)
从零开始学习 Java:简单易懂的入门指南之Map集合(二十三)
|
3月前
|
存储 Go 容器
【golang】对键值有顺序要求时,不要使用 map
【golang】对键值有顺序要求时,不要使用 map
82 0
SpringMVC入门到实战------5、域对象共享数据 Request、Session、Application、Model、ModelAndView、Map、ModelMap的详细使用及代码实例
这篇文章详细解释了在IntelliJ IDEA中如何使用Mute Breakpoints功能来快速跳过程序中的后续断点,并展示了如何一键清空所有设置的断点。
SpringMVC入门到实战------5、域对象共享数据 Request、Session、Application、Model、ModelAndView、Map、ModelMap的详细使用及代码实例
|
4天前
|
Java Serverless Go
Golang 开发函数计算问题之在 Golang 中避免 "concurrent map writes" 异常如何解决
Golang 开发函数计算问题之在 Golang 中避免 "concurrent map writes" 异常如何解决
|
2月前
|
Go
GOLANG MAP 查找
GOLANG MAP 查找
|
2月前
|
存储 Go 索引
GOLANG MAP 底层实现
GOLANG MAP 底层实现
|
2月前
|
Kubernetes Go 云计算
Golang 入门技术文档
**Golang 技术文档摘要:** Golang,由Google开发,是一种静态强类型、编译型语言,广泛应用于云计算、网络编程和分布式系统。本文档介绍了Golang的基础和特性,包括安装配置、 HelloWorld 示例、基本语法,如变量推导、函数多返回值和并发编程(goroutine、channel)。Golang的并发模型基于轻量级goroutine和channel,支持高效并发处理。此外,文档还提及了接口和多态性,展示了如何使用接口实现类型间的交互。Golang在Docker、Kubernetes等项目中得到应用,适用于后端服务开发。【6月更文挑战第9天】
29 1
|
2月前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【6月更文挑战第18天】Java Map是键值对集合,接口有HashMap、TreeMap、LinkedHashMap等实现。创建Map如`Map<String, Integer> map = new HashMap<>();`。访问修改值用`get()`和`put()`。遍历Map用`entrySet()`配合for-each。多线程下用ConcurrentHashMap。优化包括选对实现类、设置容量和负载因子、避免遍历时修改。本文助你精通Map使用。
74 0
|
3月前
|
存储 编译器 Go
Golang深入浅出之-掌握Go语言Map:初始化、增删查改与遍历
【4月更文挑战第21天】Go语言中的`map`提供快速的键值对操作,包括初始化、增删查改和遍历。初始化时,推荐使用`make()`函数,如`make(map[string]int)`。插入和查询键值对直接通过索引访问,更新则重新赋值。删除键值对需用`delete()`函数,确保键存在。遍历map常用`for range`,注意避免在遍历中修改map。了解这些并避免易错点,能提升代码效率和可读性。
44 1
Golang深入浅出之-掌握Go语言Map:初始化、增删查改与遍历
|
3月前
|
存储 Serverless C++
【C++入门到精通】哈希 (STL) _ unordered_map _ unordered_set [ C++入门 ]
【C++入门到精通】哈希 (STL) _ unordered_map _ unordered_set [ C++入门 ]
26 1