Head First Go - 第七部分映射

本文详细介绍了Go语言中的映射(Map)特性,包括映射的定义、字面量创建、零值、判断是否赋值以及for...range循环的使用方法。映射提供了一种高效的方式来存储和检索键值对,对于统计字符串出现次数等场景尤为适用。文章还强调了未赋值映射的零值为nil,以及如何通过for...range循环遍历映射。
摘要由CSDN通过智能技术生成


1. 映射

现在有一个需求,我们要统计一个数组中,这些字符串出现了多少次,在没有映射之前,我们的思路可以是创建两个切片类,然后一个用来存储数组中的字符串到不同下标,再用另一个切片来存储这个字符串的出现的次数,这样两个切片相互映射。但是这样有一个缺点就是当数据量很大的时候,显然是比较耗时的,那么我们就可以使用到 Go 里面的 map 集合来存储。

定义:var myMap map[string] int,可以看到定义的方法 map是关键字,[string] 是key,int是value

package main

import "fmt"

func main() {
	var myMap map[string]int     //声明一个映射
	myMap = make(map[string]int) //真正创建一个映射

	fmt.Printf("myMap: %v\n", myMap)	//myMap: map[]
}

下面短变量声明的方式更加方便:

package main

import "fmt"

func main() {
	ranks := make(map[string]int)
	fmt.Printf("ranks: %v\n", ranks)	//ranks: map[]
}

映射的赋值和取值的语法和数组和切片的赋值和取值有点类似。但是数组和切片仅允许使用整型作为元素索引,而映射可以选择几乎所有的类型来作为主键。

package main

import "fmt"

func main() {
	ranks := make(map[string]int)
	ranks["gold"] += 1
	ranks["silver"] += 1
	ranks["bronze"] += 1

	fmt.Printf("ranks: %v\n", ranks)	//ranks: map[bronze:1 gold:1 silver:1]
}

取值也是和数组的用法一样的

package main

import "fmt"

func main() {
	ranks := make(map[string]int)
	ranks["gold"] += 1
	ranks["silver"] += 1
	ranks["bronze"] += 1

	fmt.Println(ranks["bronze"])		//1
	fmt.Println(ranks["silver"])		//1
	fmt.Println(ranks["gold"])			//1
}



2. 映射字面量

创建字面量映射:

package main

import "fmt"

func main() {
	myMap := map[string]int{"a":12, "b":13}
	fmt.Printf("myMap: %v\n", myMap)		//myMap: map[a:12 b:13]

	elements := map[string]string{
		"H":"Hydrogen",
		"Li":"Lithium",
	}
	fmt.Printf("elements: %v\n", elements)	//elements: map[H:Hydrogen Li:Lithium]
}

我们也可以创建一个空的映射:emptyMap := map[string]float64{}



3. 映射中的零值

Go语言中不需要put,而是直接使用就行了,只要创建了就算拿了不存在的key,也会初始化为零值

package main

import "fmt"

func main() {
	counters := make(map[string]int)
	fmt.Printf("counters[\"aaa\"]: %v\n", counters["aaa"])	//counters["aaa"]: 0

	strings := make(map[string]string)
	fmt.Printf("strings[\"aaa\"]: %#v\n", strings["aaa"])	//strings["aaa"]: ""
}



4. 映射变量的零值是nil

如果我们声明了一个映射但是没有赋值,那么这个映射就是nil,再使用之前我们必须调用make函数进行创建映射

package main

import "fmt"

func main() {
	var nilMap map[int]string
	fmt.Printf("nilMap: %#v\n", nilMap)		//nilMap: map[int]string(nil)

	nilMap[3] = "aaa"	//panic: assignment to entry in nil map

}



5. 如何区分已经赋值的值和零值

有时候虽然有零值,但是我们还是要区分到底这个key有没有赋值过。有这么一个场景:在根据分数判断是否及格的时候,我们传入一个名字,可能这个名字还没有存入map里面,但是由于初值赋值为0了,所以得到的结果就会认为是不及格,那么如何解决?

map集合获取value的时候会返回两个参数,第一个是value,第二个是是否已存在,那么我们就可以通过第二个参数来判断,代码如下

package main

import "fmt"

func main() {
	counters := map[string]int{"a":3, "b":2}
	
	var value int
	var ok bool
	value, ok = counters["a"]
	fmt.Println(value, ok)		//3 true

	value, ok = counters["b"]
	fmt.Println(value, ok)		//2 true 

	value, ok = counters["c"]
	fmt.Println(value, ok)		//0 false
}

所以这种写法就是说尽管我们赋值成0了,但是还是可以通过第二个参数判断出来有没有赋值过



6. 对映射进行for…range循环

变量的格式:for key, value := range myMap{}, key就是key,value就是value,myMap就是map集合

package main

import "fmt"

func main() {
	counters := map[string]int{"a":3, "b":2}
	for key, value:=range counters{
		fmt.Println(key, ":", value)
		//a : 3  
		//b : 2 
	}
}

如果需要循环所有的键,你可以忽略它对应的值变量:

package main

import "fmt"

func main() {
	counters := map[string]int{"a":3, "b":2, "c":4, "d":5}

	//单单处理值
	for value :=range counters{
		fmt.Printf("value: %v\n", value)
		//value: a
		//value: b
		//value: c
		//value: d
	}
}

如果需要值,那么可以使用空白标识符处理键:

package main

import "fmt"

func main() {
	counters := map[string]int{"a":3, "b":2, "c":4, "d":5}

	//单单处理值
	for _, grade :=range counters{
		fmt.Printf("grade: %v\n", grade)	
		//grade: 3
		//grade: 2
		//grade: 4
		//grade: 5
	}
}

有一点就是说for...range不是有序的,当我们运行次数够多的时候,会发现出现这种输出结果,和之前的不是一样的,结论就是:如果我们需要输出有序的集合顺序,就要自己定义,但是如果我们对输出顺序没有需求,就可以使用 for…range

在这里插入图片描述





如有错误,欢迎指出!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值