map 使用细节和陷阱|学习笔记

简介: 快速学习 map 使用细节和陷阱

开发者学堂课程【Go语言核心编程 - 基础语法、数组、切片、Map:map 使用细节和陷阱】与课程紧密联系,让用户快速学习知识

课程地址:https://developer.aliyun.com/learning/course/625/detail/9662


map 使用细节和陷阱

内容介绍:

一、总结map使用细节

二、map是引用类型

三、map的容量自动扩容

四、map的value使用结构体

一、总结map使用细节

接下来介绍 map 的使用细节,这里给大家总结了3点,都非常重要。

1.map 是引用类型,遵守引用类型传递的机制,在一个函数接收 map,修改后,会直接修改原来的 map【案例演示】

2.map 的容量达到后再想 map 增加元素,会自动扩容,并不会发生 panic,也就是说map 能动态的增长键值对(key-value)索例演示】

3.map 的 value 也经常使用 struct 类型,更适合管理复杂的数据(比前面value是一个map更好),比如 value 为 Student 结构体【案例演示,因为还没有学结构体,体验一下即可】


二、map是引用类型

来看一下 map 使用细节有哪些地方。第一个,首先要清楚的知道 map 是一个引用类型的数据,因此它就会遵守信用类型传递的机制,也就是说如果用一个函数接收map,修改过后,会直接修改原来的 map。也就是说 map 是引用类型的,这点要注意,跟切片一样,切片是引用类型,map也是引用类型。

举个例子说明特点新建一个文件夹叫 mapdetails,然后新建一个文件名叫main.go。在之前的文件里复制一个通用的代码过来,代码如下:

package main

import (

“fmt”

)

func main() {

}

先讲map细节的第一点,测试这个特点是否正确。写一个函数 modify,在这里接收一个 map,类型是 int 类型,代码如下:

func modify(map1 map[int]int) {

map1[10] = 900

//下标为10,改成了900

//但是要确保有一个key为10

}

在主函数里声明一个 map,代码如下:

map1 := make(map[int]int)

//

make 一个 map[int]int 类型的 map

map1[1] = 90

//第一个放的key为1,map等于90

map1[2] = 88 

//key为2,map等于88

map1[10] = 1  

//key为10,map等于1

map1[20] = 2  

//key为20,map等于2

modify(map1)  

//调用modify的时候把map传给它

fmt.Println(map1)  //看看结果,map[10] = 900,说明map是引用类型

输出观察 key 为10的这个元素对应的值是1还是900。如果输出的是900就说明它的确是引用传递类型;如果仍然保存是1,那就说明它是默认只拷贝、只传递了。

运行这段阶段代码,在 cmd.exe里输入以下命令回车:

cd..

cd mapdetails

go run main.go

输出结果是:

image.png

map[1:90 2:88 10:900 20:2]  //输出的结果和分析的结果是一样的

可以看到key为10的变成了900,也就是说当把 map 传递给 modify 函数过后,modify 里的修改会直接影响到 map 里面的 map1,从而说明 map 是引用类型。


三、map的容量自动扩容

再来看 map 使用的第二个细节。map 容量达到后,再想 map 增加元素,会自动扩容,并不会发生panic。但是切片不可以,切片得用 append 才可以。也就是说map 能动态的增长键值对(key-value)。

案例演示:

map1 := make(map[int]int, 2)  

//make一个map[int]int类型的map,默认容量是2

map1[1] = 90

map1[2] = 88

map1[10] = 1

map1[20] = 2 

 //key为20,map等于2

modify(map1)

//调用 modify 的时候把 map 传给它

fmt.Println(map1)

可以看到在在map1[10]的时候已经超过了2了,但是没有报错,此时是可以运行的,运行结果是:

89db7cf037cf47818ed3e00c9f719cf2.png

map[10:900 20:2 1:90 2:88]

这说明map确实可以自动扩容。


四、map的value使用结构体

再看第三个细节,map的value也经常使用struct类型(struct就是结构体),更适合管理复杂的数据(比前面是一个map更好),比如value为Student结构体【因为还没有学结构体,体验一下即可】。(其实 map 这个值用结构体用的更多,所以这里只是写一段代码体验一下)

案例演示:

对前面的案例进行修改,map 的 key 还是用的学号,然后它的值用结构体来完成。

这里将要求粘贴过来:

// map 的 value 也经常使 struct 类型,

//更适合管理复杂的数据(比前面是一个map更好),

//比如 value 为 Student 结构体【因为还没有学结构体,体验一下即可

//(1)map 的 key 为学生的学号,是唯一的

//(2)map 的 value 为结构体,包含学生的名字,年龄,地址

第一步要定义一个结构体:

//定义一个学生结构体

type Stu struct {

Name string //定义名字

Age int  //定义年龄

Address string  //定义地址

}  

//这就是一个学生结构体

声明一个map:

students := make(map[string]Stu, 10)  //放10个学生进去,make 一个这样的 map,map 的 key 是 string,map 的值是 Stu 结构体。

//创建2个学生

stu1 := Stu{”tom”, 18,”北京”} //这里做了简单化处理,第一个学生名字是tom,年龄是18,地址是北京

stu2 := Stu{“mary”, 28,”上海”}  第一个学生名字是 mary,年龄是28,地址是上海

//现在要将两个学生交到 string 这个值中

students[“no1”] = stu1  //学号它的 key 是 number1,是 stu1这个学生

students[“no2”] = stu2  //学号它的 key 是 number2,是 stu2这个学生

fmt.Println(students)  

//输出这个 students,观察此时此刻是否已经用这个 map 把这个学生(string)保留起来,也就是说这个值Stu已经是个结构体了,这样肯定是更好保存一个学生的信息。

在 cmd.exe 里输入命令 go run main.go 回车得到:

3f4b1c62f4574db591168f1513837e9e.png

map[1:90 2:88 10=900 20:2]

map [no1:<tom 18北京>  no2:<mary 28 上海>] 

可以很清晰的看出 map 里面有一个 no1,key 为no1,它是一个结构体:tom18北京;第二个学生是 no2,它的结构体是 mary,28,上海。这样就会更好一点,因为将来结构体的数据可以很轻松的增加它的储存部分,比如再增加一个属性就很轻松了。

再讲如何遍历一个学生,想把每一个学生具体的信息做出来:

//遍历各个学生信息

for k, v := range students {

//for 第一个把key遍历出来,把值遍历出来,k就是学生的编号,v就是一个结构体fmt.Printf(“学生的编号是%v \n”, k) 

//每输出一个就换行

fmt.Printf(“学生的名字是%v \n”, v.Name)

fmt.Printf(“学生的年龄是%v \n”, v.Age)

fmt.Printf(“学生的地址是%v \n”, v.Address)

fmt.Println()  //最后再换一行

}

执行看遍历是否成功,在 cmd.exe 里输入命令 go run main.go 回车得到:

f946ff1586634624a6585aa426af73ef.png

map[2:88 10:900 20:2 1:90]

map[no1:<tom 18 北京>  no2:<mary 28 上海>]

学生的编号是no1

学生的名字是tom

学生的年龄是18

学生的地址是北京

学生的编号是no2

学生的名字是mary

学生的年龄是28

学生的地址是上海

可以看出信息是非常清晰的,第一个学生编号是 no1,名字、年龄、地址等都有;第二个学生编号是 no2,名字、年龄等如上。

这里就讲了 map 使用的第三个细节,在实际开发中 value 更多的情况下用的是结构体类型,而且这种方式来保存或者管理数据也更加的方便,更加的灵活。

关于 map 使用细节就讲完了,尤其要注意第三点,还有就是 map 是引用类型,map 的容量会自动增加。

相关文章
|
1月前
|
存储 安全 Java
|
1月前
|
存储 Java 程序员
Java数组全套深入探究——基础知识阶段2、数组的定义语法
Java数组全套深入探究——基础知识阶段2、数组的定义语法
39 0
|
存储 C++ 容器
C++ 第九节——map/set(用法+底层原理+模拟实现)
们需要知道的是,Map和Set的底层都是红黑树。
624 1
C++ 第九节——map/set(用法+底层原理+模拟实现)
|
8月前
|
存储 Go
善用这些技巧 Go语言map元素删除那么简单
善用这些技巧 Go语言map元素删除那么简单
1172 0
|
10月前
|
前端开发
前端学习笔记202305学习笔记第二十八天-什么是对象结构 set map之13
前端学习笔记202305学习笔记第二十八天-什么是对象结构 set map之13
30 0
前端学习笔记202305学习笔记第二十八天-什么是对象结构 set map之13
|
10月前
|
前端开发
前端学习笔记202305学习笔记第二十八天-什么是对象结构 set map之14
前端学习笔记202305学习笔记第二十八天-什么是对象结构 set map之14
34 0
|
前端开发
前端学习案例2-weakMap的用法2
前端学习案例2-weakMap的用法2
45 0
|
存储 索引
抛砖引玉:分享9个map“可能常用”的小栗子。
抛砖引玉:分享9个map“可能常用”的小栗子。
|
存储 JavaScript Scala
从map函数引发的讨论
从map函数引发的讨论
从map函数引发的讨论
|
Go 开发者
map 使用细节和陷阱|学习笔记
快速学习 map 使用细节和陷阱
165 0
map 使用细节和陷阱|学习笔记