什么是 map?

Map 是 Go 中的内置类型,它将键与值绑定到一起。可以通过键获取相应的值。

如何创建 map?

可以通过将键和值的类型传递给内置函数 make 来创建一个 map。语法为:make(map[KeyType]ValueType)。(译者注:map 的类型表示为 map[KeyType]ValueType)例如:

personSalary := make(map[string]int)

上面的代码创建了一个名为 personSalary 的 map。其中键的类型为 string,值的类型为 int。

map 的 0 值为 nil。试图给一个 nil map 添加元素给会导致运行时错误。因此 map 必须通过 make 来初始化(译者注:也可以使用速记声明来创建 map,见下文)。

package main

import (
"fmt"
) func main() {
var personSalary map[string]int
if personSalary == nil {
fmt.Println("map is nil. Going to make one.")
personSalary = make(map[string]int)
}
}

上面的程序中,personSalary 为 nil,因此使用 make 初始化它。程序的输出为:map is nil. Going to make one.

向 map 中插入元素

插入元素给 map 的语法与数组相似。下面的代码插入一些新的元素给 map personSalary

package main

import (
"fmt"
) func main() {
personSalary := make(map[string]int)
personSalary["steve"] =
personSalary["jamie"] =
personSalary["mike"] =
fmt.Println("personSalary map contents:", personSalary)
}

上面的程序输出:personSalary map contents: map[steve:12000 jamie:15000 mike:9000]

也可以在声明时初始化一个数组:

package main

import (
"fmt"
) func main() {
personSalary := map[string]int {
"steve": ,
"jamie": ,
}
personSalary["mike"] =
fmt.Println("personSalary map contents:", personSalary)
}

上面的程序在声明 personSalary 的同时向其中插入了两个元素。接着插入了一个以 "mike" 为键的元素。程序的输出为:

personSalary map contents: map[steve: jamie: mike:] 

string 并不是可以作为键的唯一类型,其他所有可以比较的类型,比如,布尔类型,整型,浮点型,复数类型都可以作为键。如果你想了解更多关于可比较类型的话,请参阅:http://golang.org/ref/spec#Comparison_operators

访问 map 中的元素

现在我们已经添加了一些元素给 map,现在让我们学习如何从 map 中提取它们。根据键获取值的语法为:map[key],例如:

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": ,
"jamie": ,
}
personSalary["mike"] =
employee := "jamie"
fmt.Println("Salary of", employee, "is", personSalary[employee])
}

上面的程序非常简单。员工 jamie 的工资被取出并打印。程序的输出为:Salary of jamie is 15000

如果一个键不存在会发生什么?map 会返回值类型的 0 值。比如如果访问了 personSalary 中的不存在的键,那么将返回 int 的 0 值,也就是 0。

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": ,
"jamie": ,
}
personSalary["mike"] =
employee := "jamie"
fmt.Println("Salary of", employee, "is", personSalary[employee])
fmt.Println("Salary of joe is", personSalary["joe"])
}

上面的程序输出为:

Salary of jamie is
Salary of joe is

上面的程序返回 joe 的工资为 0。我们没有得到任何运行时错误说明键 joe 在 personSalary 中不存在。

我们如何检测一个键是否存在于一个 map 中呢?可以使用下面的语法:

value, ok := map[key]  

上面的语法可以检测一个特定的键是否存在于 map 中。如果 ok 是 true,则键存在,value 被赋值为对应的值。如果 ok为 false,则表示键不存在。

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": ,
"jamie": ,
}
personSalary["mike"] =
newEmp := "joe"
value, ok := personSalary[newEmp]
if ok == true {
fmt.Println("Salary of", newEmp, "is", value)
} else {
fmt.Println(newEmp,"not found")
} }

在上面的程序中,第 15 行,ok 应该为 false 因为 joe 不存在。因此程序的输出为:

joe not found  

range for 可用于遍历 map 中所有的元素(译者注:这里 range 操作符会返回 map 的键和值)。

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": ,
"jamie": ,
}
personSalary["mike"] =
fmt.Println("All items of a map")
for key, value := range personSalary {
fmt.Printf("personSalary[%s] = %d\n", key, value)
} }

上面的程序输出如下:

All items of a map
personSalary[mike] =
personSalary[steve] =
personSalary[jamie] =

值得注意的是,因为 map 是无序的,因此对于程序的每次执行,不能保证使用 range for 遍历 map 的顺序总是一致的。

删除元素

delete(map, key) 用于删除 map 中的 key。delete 函数没有返回值。

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": ,
"jamie": ,
}
personSalary["mike"] =
fmt.Println("map before deletion", personSalary)
delete(personSalary, "steve")
fmt.Println("map after deletion", personSalary) }

上面的程序删除以 steve 为键的元素。程序输出为:

map before deletion map[steve: jamie: mike:]
map after deletion map[mike: jamie:]

map 的大小

用内置函数 len 获取 map 的大小:

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": ,
"jamie": ,
}
personSalary["mike"] =
fmt.Println("length is", len(personSalary)) }

上面程序中,len(personSalary) 获取 personSalary 的大小。上面的程序输出:length is 3

map 是引用类型

切片一样,map 是引用类型。当一个 map 赋值给一个新的变量,它们都指向同一个内部数据结构。因此改变其中一个也会反映到另一个:

package main

import (
"fmt"
) func main() {
personSalary := map[string]int{
"steve": ,
"jamie": ,
}
personSalary["mike"] =
fmt.Println("Original person salary", personSalary)
newPersonSalary := personSalary
newPersonSalary["mike"] =
fmt.Println("Person salary changed", personSalary)
}

上面的程序中,第 14 行,personSalary 赋值给 newPersonSalary。下一行,将 newPersonSalary 中 mike 的工资改为 18000。那么在 personSalary 中 mike 的工资也将变为 18000。程序的输出如下:

Original person salary map[steve: jamie: mike:]
Person salary changed map[jamie: mike: steve:]

将 map 作为参数传递给函数也是一样的。在函数中对 map 的任何修改都会影响在调用函数中看到。

Golang教程:Map的更多相关文章

  1. Golang基础教程——map使用篇

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第7篇文章,我们来聊聊golang当中map的用法. map这个数据结构我们经常使用,存储的是key-value的键 ...

  2. Golang中map的三种声明方式和简单实现增删改查

    package main import ( "fmt" ) func main() { test3 := map[string]string{ "one": & ...

  3. 总结golang之map

    总结golang之map 2017年04月13日 23:35:53 趁年轻造起来 阅读数:18637 标签: golangmapgo 更多 个人分类: golang   版权声明:本文为博主原创文章, ...

  4. golang 中 map 转 struct

    golang 中 map 转 struct package main import ( "fmt" "github.com/goinggo/mapstructure&qu ...

  5. golang之map的使用声明

    1.map的基本介绍 map是key-value数据结构,又称为字段或者关联数组.类似其它编程语言的集合,在编程中是经常使用到的 2.map的声明 1)基本语法 var map 变量名 map[key ...

  6. Golang:sync.Map

    由于map在gorountine 上不是安全的,所以在大量并发读写的时候,会出现错误. 在1.9版的时候golang推出了sync.Map. sync.Map 通过阅读源码我们发现sync.Map是通 ...

  7. Golang教程:变量

    声明单一变量 声明一个变量的语法为:var name type,例如 package main import "fmt" func main() { var age int // ...

  8. Golang教程:goroutine信道

    在上一篇教程中,我们讨论了如何使用协程实现并发.在这篇教程中,我们将讨论信道以及如何使用信道实现协程间通信. 什么是信道 信道(Channel)可以被认为是协程之间通信的管道.与水流从管道的一端流向另 ...

  9. 手把手golang教程【二】——数组与切片

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第五篇,这一篇我们将会了解golang中的数组和切片的使用. 数组与切片 golang当中数组和C++中的定义类似, ...

随机推荐

  1. HBase入门篇

    目录: 1-HBase的安装 2-Java操作HBase例子 3-HBase简单的优化技巧 4–存储 5(集群) -压力分载与失效转发 6 -白话MySQL(RDBMS)与HBase之间 7 -安全& ...

  2. c#设计模式系类:亨元模式

    一.引言 在软件开发过程中,如果我们需要重复使用某个对象的时候,如果我们重复地使用new创建这个对象的话,这样我们在内存就需要多次去申请内存空间了,这样可能出现内存使用越来越多的情况,这样的问题是非常 ...

  3. atan2()如何转换为角度

    atan2()如何转换为角度 Math.atan2()函数返回点(x,y)和原点(0,0)之间直线的倾斜角.那么如何计算任意两点间直线的倾斜角呢?只需要将两点x,y坐标分别相减得到一个新的点(x2-x ...

  4. mongodb driver2.5环境注意事项

    mongodb driver2.5环境注意事项 一.问题: 如果使用vs2012开发就会报这个错误: 未能加载文件或程序集“System.Runtime.InteropServices.Runtime ...

  5. 开发者都应该使用的10个C++11特性

    摘要: 在C++11新标准中,语言本身和标准库都增加了很多新内容,本文只涉及了一些皮毛.不过我相信这些新特性当中有一些,应该成为所有C++开发者的常规装备.你也许看到过许多类似介绍各种C++11特性的 ...

  6. ZJOI round1游记

    Day 0 到镇海报道了 大佬们太多了--话说镇海的晚饭还真好吃啊-- 听说某人要咱去找bwh--不过咱和他也不是很熟啊--还是算了吧--(才不是因为嫌麻烦懒得去呢) 晚上吃完晚饭之后在镇海校园里参观 ...

  7. 十大javaScript框架

    http://blog.163.com/hongshaoguoguo@126/blog/static/180469812012102645931862/ Prototype特点:一个非常优雅的JS库, ...

  8. 虚拟机安装CentOS,网络配置

    CentOS6和CentOS7,基础配置差不多. 安装CentOs6,过程:略: 安装完成后,系统默认启用动态ip,每次重启主机IP可能就会变化,搭配Xftp和Xshell工具会很难受,因此设置静态I ...

  9. 在iOS7中修改键盘Return键的类型

    今天将之前运行在iOS7之前的一段代码拿出来,在iOS7的机器上运行,发现键盘上的ReturnKeyType不能被修改了. 经过几番查找资料,了解到iOS7中UISearchBar的结构发生了变化,将 ...

  10. CocoaPods的PodSpec.json文件用法

    最近有时候用最新的CocoaPod的第三方库,有时候发现CocoaPod.org能搜到那个Podfile,但是每次在终端Pod search xxx,每次都搜不到,原来是本地的Podspec没用更新, ...