Golang map映射的用法


Posted in Golang onApril 22, 2022

1. 什么是 map

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值

Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的

Map 是引用类型,必须初始化才能使用。其中,key的类型除了切片等引用类型,其他类型都可以;而value则可使用所有类型的值

2. 创建 map

可以通过make()创建map,它会先创建好底层数据结构,然后再创建map,并让map指向底层数据结构

my_map := make(map[string]int)

[string]表示map的key的数据类型

int表示key对应的值

直接通过大括号创建并初始化赋值:

// 空map
my_map := map[string]string{}
 
// 初始化赋值
my_map := map[string]string{"Red": "#da1337","Orange": '#e95a22"}
 
// 格式化赋值
my_map := map[string]int{
"Java":11,
"Perl":8,
"Python":13, // 注意结尾的逗号不能少
}

注意:

其中map的key可以是任意内置的数据类型(如int),或者其它可以通过 == 进行等值比较的数据类型,如interface和指针可以,slice、数组、map、struct类型都不能作为key ,并且key必须唯一。

但value基本可以是任意类型,例如嵌套一个slice到map中:

my_map := map[string][]int{}

3. 访问 map

访问map中的元素时,指定它的key即可,注意string类型的key必须加上引号:

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 10,
        "2": 20,
        "3": 30,
        "4": 40,
    }
 
    //访问
    fmt.Println(my_map["1"])
    fmt.Println(my_map)
 
    fmt.Println("")
 
    //赋值已有的key & value
    my_map["2"] = 50
    fmt.Println(my_map["2"])
    fmt.Println(my_map)
 
    fmt.Println("")
 
    //赋值新的key&value
    my_map["5"] = 66
    fmt.Println(my_map["5"])
    fmt.Println(my_map)
}

输出结果

10
map[1:10 2:20 3:30 4:40]
50
map[1:10 2:50 3:30 4:40]
66
map[1:10 2:50 3:30 4:40 5:66]

4. nil map和空map

空map是不做任何赋值的map:

// 空map
package main
 
import "fmt"
 
func main() {
    my_map := map[string]string{}
 
    fmt.Println(my_map)
}

输出结果

map[]

nil map,它将不会做任何初始化,不会指向任何数据结构:

// nil map
var my_map map[string]string

nil map和empty map的关系,就像nil slice和empty slice一样,两者都是空对象,未存储任何数据,但前者不指向底层数据结构,后者指向底层数据结构,只不过指向的底层对象是空对象。

使用println输出看下即可知道:

package main
 
func main() {
    var nil_map map[string]string
    println(nil_map)
 
    emp_map := map[string]string{}
    println(emp_map)
}

输出结果:

0x0
0xc04204de38

所以,map类型实际上就是一个指针。

5. map中元素的返回值

当访问map中某个元素的时候,有两种返回值的格式:

value := my_map["key"]
value,exists := my_map["key"]

第一种很好理解,就是检索map中key对应的value值。如果key不存在,则value返回值对应数据类型的0。例如int为数值0,布尔为false,字符串为空""。

第二种不仅返回key对应的值,还根据key是否存在返回一个布尔值赋值给exists变量。所以,当key存在时,value为对应的值,exists为true;当key不存在,value为0(同样是各数据类型所代表的0),exists为false。

看下例子:

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 10,
        "2": 20,
        "3": 30,
        "4": 40,
    }
    a := my_map["1"]
    b, exists1 := my_map["2"]
    c, exists2 := my_map["5"]
    fmt.Println(a)
    fmt.Println(b, exists1)
    fmt.Println(c, exists2)
}

上面将输出如下结果:

10
20 true
0 false

在Go中设置类似于这种多个返回值的情况很多,即便是自己编写函数也会经常设置它的exists属性。

6. len()和delete()

len()函数用于获取map中元素的个数,即有多个少key。delete()用于删除map中的某个key。

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 10,
        "2": 20,
        "3": 30,
        "4": 40,
    }
 
    fmt.Printf("删除前长度为%d\n", len(my_map))
    delete(my_map, "1")
    fmt.Printf("删除后长度为%d", len(my_map))
}

输出结果如下

删除前长度为4
删除后长度为3

7. 测试map中元素是否存在

两种方式可以测试map中是否存在某个key:

① 根据map元素的第二个返回值来判断

② 根据返回的value是否为0(不同数据类型的0不同)来判断

方式一:直接访问map中的该元素,将其赋值给两个变量,第二个变量就是元素是否存在的修饰变量。

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 10,
        "2": 20,
        "3": 30,
        "4": 40,
    }
     
//方法1
/* value, exists := my_map["1"]
    if exists {
        fmt.Println("存在", value)
    }
 */
 
 
    //方法2
    if value, exists := my_map["1"]; exists {
        fmt.Printf("值存在, value=%d", value)
    }
}

输出结果如下

值存在, value=10

方式二:根据map元素返回的value判断。因为该map中的value部分是int类型,所以它的0是数值的0。

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 10,
        "2": 20,
        "3": 30,
        "4": 40,
    }
 
    value := my_map["5"]
    if value == 0 {
        fmt.Println("不存在")
    }
}

输出结果如下

不存在

如果map的value数据类型是string,则判断是否为空:

package main
 
import "fmt"
 
func main() {
    my_map := map[string]string{
        "1": "book",
        "2": "games",
        "3": "computer",
    }
 
    value := my_map["5"]
    if value == "" {
        fmt.Println("不存在")
    }
}

输出结果如下

不存在

由于map中的value有可能本身是存在的,但它的值为0,这时就会出现误判断。例如下面的"3",它已经存在,但它对应的值为0

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 22,
        "2": 11,
        "3": 0,
    }
 
    value := my_map["3"]
    if value == 0 {
        fmt.Println("不存在")
    }
}

输出结果如下

不存在

所以,应当使用第一种方式进行判断元素是否存在。

8. 迭代遍历 map

因为map是key/value类型的数据结构,key就是map的index,所以range关键字对map操作时,将返回key和value。

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 22,
        "2": 11,
        "3": 0,
        "4": 55,
        "5": 66,
    }
 
    for k, v := range my_map {
        fmt.Printf("key=%s, value=%d\n", k, v)
    }
}

输出结果如下

key=1, value=22
key=2, value=11
key=3, value=0
key=4, value=55
key=5, value=66

如果range迭代map时,只给一个返回值,则表示迭代map的key:

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 22,
        "2": 11,
        "3": 0,
        "4": 55,
        "5": 66,
    }
 
    for key := range my_map {
        fmt.Println("key=", key)
    }
}

输出结果

key= 1
key= 2
key= 3
key= 4
key= 5

9. 获取map中所有的key

Go中没有提供直接获取map所有key的函数。所以,只能自己写,方式很简单,range遍历map,将遍历到的key放进一个slice中保存起来。

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "Java":   11,
        "Perl":   8,
        "Python": 13,
        "Shell":  23,
    }
 
    // 保存map中key的slice
    // slice类型要和map的key类型一致
    keys := make([]string,0,len(my_map))
 
    // 将map中的key遍历到keys中
    for map_key,_ := range my_map {
        keys = append(keys,map_key)
    }
 
    fmt.Println(keys)
}

注意上面声明的slice中要限制长度为0,否则声明为长度4、容量4的slice,而这4个元素都是空值,而且后面append()会直接对slice进行一次扩容,导致append()后的slice长度为map长度的2倍,前一半为空,后一般才是map中的key。

10. 传递map给函数

map是一种指针,所以将map传递给函数,仅仅只是复制这个指针,所以函数内部对map的操作会直接修改外部的map。

例如,test()用于给map的key对应的值加1。

package main
 
import "fmt"
 
func main() {
    my_map := map[string]int{
        "1": 22,
        "2": 11,
        "3": 0,
        "4": 55,
        "5": 66,
    }
    fmt.Println("修改之前key=", my_map["3"])
    fmt.Println(my_map)
 
    fmt.Println("")
 
    test(my_map, "3")
    fmt.Println("修改之后key=", my_map["3"])
    fmt.Println(my_map)
 
}
 
func test(m map[string]int, key string) {
    m[key] += 1
}

输出结果如下

修改之前key= 0
map[1:22 2:11 3:0 4:55 5:66]
 
修改之后key= 1
map[1:22 2:11 3:1 4:55 5:66]

到此这篇关于Go语言学习之映射(map)的用法详解的文章就介绍到这了!


Tags in this post...

Golang 相关文章推荐
Go各时间字符串使用解析
Apr 02 Golang
golang判断key是否在map中的代码
Apr 24 Golang
Golang 实现超大文件读取的两种方法
Apr 27 Golang
golang 如何通过反射创建新对象
Apr 28 Golang
Golang生成Excel文档的方法步骤
Jun 09 Golang
golang中字符串MD5生成方式总结
Jul 04 Golang
深入理解go缓存库freecache的使用
Feb 15 Golang
golang实现浏览器导出excel文件功能
Mar 25 Golang
golang操作rocketmq的示例代码
Apr 06 Golang
Golang 遍历二叉树
Apr 19 Golang
Go本地测试解耦任务拆解及沟通详解Go本地测试的思路沟通的重要性总结
Jun 21 Golang
go goth封装第三方认证库示例详解
Aug 14 Golang
Golang bufio详细讲解
Apr 21 #Golang
Go获取两个时区的时间差
Apr 20 #Golang
Golang jwt身份认证
实现GO语言对数组切片去重
Apr 20 #Golang
Golang日志包的使用
Apr 20 #Golang
Golang获取List列表元素的四种方式
Apr 20 #Golang
Golang 对es的操作实例
Apr 20 #Golang
You might like
我的论坛源代码(四)
2006/10/09 PHP
php二分法在IP地址查询中的应用
2008/08/12 PHP
php HtmlReplace输入过滤安全函数
2010/07/03 PHP
php通过ksort()函数给关联数组按照键排序的方法
2015/03/18 PHP
Yii框架 session 数据库存储操作方法示例
2019/11/18 PHP
Jquery.LazyLoad.js修正版下载,实现图片延迟加载插件
2011/03/12 Javascript
深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP
2012/01/15 Javascript
Jquery之Bind方法参数传递与接收的三种方法
2014/06/24 Javascript
Javscript调用iframe框架页面中函数的方法
2014/11/01 Javascript
Javascript实现Web颜色值转换
2015/02/05 Javascript
JavaScript入门教程之引用类型
2016/05/04 Javascript
基于jQuery实现仿微博发布框字数提示
2016/07/27 Javascript
vue实现搜索功能
2019/05/28 Javascript
LayUI动态设置checkbox不显示的解决方法
2019/09/02 Javascript
解决layui-table单元格设置为百分比在ie8下不能自适应的问题
2019/09/28 Javascript
微信小程序实现文件预览
2020/10/22 Javascript
微信小程序实现可拖动悬浮图标(包括按钮角标的实现)
2020/12/29 Javascript
把大数据数字口语化(python与js)两种实现
2013/02/21 Python
python使用MySQLdb访问mysql数据库的方法
2015/08/03 Python
python数据结构之链表详解
2017/09/12 Python
python实现超市扫码仪计费
2018/05/30 Python
python实现人人自动回复、抢沙发功能
2018/06/08 Python
Python+AutoIt实现界面工具开发过程详解
2019/08/07 Python
python程序 创建多线程过程详解
2019/09/23 Python
Python 日志logging模块用法简单示例
2019/10/18 Python
PyTorch中model.zero_grad()和optimizer.zero_grad()用法
2020/06/24 Python
python集合能干吗
2020/07/19 Python
泰国网上购物:Shopee泰国
2018/09/14 全球购物
中国专业的音频分享平台:喜马拉雅
2019/05/24 全球购物
编码转换,怎样实现将GB2312编码的字符串转换为ISO-8859-1编码的字符串
2014/01/07 面试题
定义一结构体变量,用其表示点坐标,并输入两点坐标,求两点之间的距离
2015/08/17 面试题
生日寿宴答谢词
2014/01/19 职场文书
土建专业大学生自荐信范文
2014/04/09 职场文书
检察院起诉意见书
2015/05/20 职场文书
公证书
2019/04/17 职场文书
SQL Server使用导出向导功能
2022/04/08 SQL Server