Go的map

本文仅是自己阅读笔记,不正确之处请多包涵和纠正。
原文The way to go

一、map的声明、赋值、初始化和make

1、map的介绍

map 是引用类型,可以使用如下声明:

var map1 map[keytype]valuetype

1、在声明的时候不需要知道 map 的长度,map 是可以动态增长的。
2、常用的 len(map1) 方法可以获得 map 中的 pair 数目,这个数目是可以伸缩的,因为 map-pairs 在运行时可以动态添加和删除。
3、未初始化的 map 的值是 nil。
4、key 可以是任意可以用 == 或者 != 操作符比较的类型,比如 string、int、float。所以数组、切片和结构体不能作为 key。但是指针和接口类型可以。(只包含内建类型的 struct 是可以作为 key,但要提供 Key() 和 Hash() 方法,这样可以通过结构体的域计算出唯一的数字或者字符串的 key)
5、value 可以是任意类型的;通过使用空接口类型,我们可以存储任意值,但是使用这种类型作为值时需要先做一次类型断言。
6、map 传递给函数的代价很小:在 32 位机器上占 4 个字节,64 位机器上占 8 个字节,无论实际上存储了多少数据。通过 key 在 map 中寻找值是很快的,比线性查找快得多,但是仍然比从数组和切片的索引中直接读取要慢 100 倍;所以如果你很在乎性能的话还是建议用切片来解决问题。

2、map的赋值与初始化

key1 对应的值可以通过赋值符号来设置为 val1:map1[key1] = val1

v := map1[key1] 可以将 key1 对应的值赋值给 v;如果 map 中没有 key1 存在,那么 v 将被赋值为 map1 的值类型的空值

  • map 可以用 {key1: val1, key2: val2} 的描述方法来初始化,就像数组和结构体一样
  • map 的初始化:var map1 = make(map[keytype]valuetype)。或者简写为:map1 := make(map[keytype]valuetype)。相当于:map1 := map[keytype]valuetype{}
  • map 是 引用类型 的: 内存用 make 方法来分配。

注意1:

不要使用 new,永远用 make 来构造 map

如果你错误的使用 new() 分配了一个引用对象,你会获得一个空引用的指针,相当于声明了一个未初始化的变量并且取了它的地址:
例如:

mapCreated := new(map[string]float32)
mapCreated["key1"] = 4.5

编译会报错:invalid operation: mapCreated["key1"] (index of type *map[string]float32).

注意2:

val1, isPresent = map1[key1]去区分 key1 不存在还是它对应的 value 就是空值的情况
isPresent 返回一个 bool 值

  • 如果 key1 存在于 map1,val1 就是 key1 对应的 value 值,并且 isPresent为true;
  • 如果 key1 不存在,val1 就是一个空值,并且 isPresent 会返回 false。

注意3:

对map1的引用map2修改也会影响到map1的值

示例:在这里插入图片描述
输出:在这里插入图片描述
注意4:

值可以是任意类型的

示例:
在这里插入图片描述
输出:
在这里插入图片描述

3、map删除键值对

从 map1 中删除 key1:直接 delete(map1, key1) 就可以。如果 key1 不存在,该操作不会产生错误。

二、map容量

和数组不同,map 可以根据新增的 key-value 对动态的伸缩,因此它不存在固定长度或者最大限制。
但是你也可以选择标明 map 的初始容量 capacity,就像这样:make(map[keytype]valuetype, cap)
示例:

map2 := make(map[string]float32, 100)

当 map 增长到容量上限的时候,如果再增加新的 key-value 对,map 的大小会自动加 1。所以出于性能的考虑,对于大的 map 或者会快速扩张的 map,即使只是大概知道容量,也最好先标明。

三、map 的for-range用法

可以使用 for 循环构造 map,第一个返回值 key 是 map 中的 key 值,第二个返回值则是该 key 对应的 value 值;

for key, value := range map1 {
	...
}

如果只关心值,可以这么使用:

for _, value := range map1 {
	...
}

如果只想获取 key,你可以这么使用:

for key := range map1 {
	fmt.Printf("key is: %d\n", key)
}

注意 map 不是按照 key 的顺序排列的,也不是按照 value 的序排列的。

四、map的排序

map 默认是无序的,不管是按照 key 还是按照 value 默认都不排序。
如果你想为 map 按key或value排序,需要将 key或 value拷贝到一个切片,再对切片排序(使用 sort 包),然后可以使用切片的 for-range 方法打印出所有的 key 和 value。

示例,按map的key排序:

package main
import (
	"fmt"
	"sort"
)

var (
	barVal = map[string]int{"alpha": 34, "bravo": 56, "charlie": 23,
							"delta": 87, "echo": 56, "foxtrot": 12,
							"golf": 34, "hotel": 16, "indio": 87,
							"juliet": 65, "kili": 43, "lima": 98}
)

func main() {
	fmt.Println("unsorted:")
	for k, v := range barVal {
		fmt.Printf("Key: %v, Value: %v / ", k, v)
	}
	keys := make([]string, len(barVal))
	i := 0
	for k, _ := range barVal {
		keys[i] = k
		i++
	}
	sort.Strings(keys)
	fmt.Println()
	fmt.Println("sorted:")
	for _, k := range keys {
		fmt.Printf("Key: %v, Value: %v / ", k, barVal[k])
	}
}

输出:

unsorted:
Key: bravo, Value: 56 / Key: echo, Value: 56 / Key: indio, Value: 87 / Key: juliet, Value: 65 / Key: alpha, Value: 34 / Key: charlie, Value: 23 / Key: delta, Value: 87 / Key: foxtrot, Value: 12 / Key: golf, Value: 34 / Key: hotel, Value: 16 / Key: kili, Value: 43 / Key: lima, Value: 98 /
sorted:
Key: alpha, Value: 34 / Key: bravo, Value: 56 / Key: charlie, Value: 23 / Key: delta, Value: 87 / Key: echo, Value: 56 / Key: foxtrot, Value: 12 / Key: golf, Value: 34 / Key: hotel, Value: 16 / Key: indio, Value: 87 / Key: juliet, Value: 65 / Key: kili, Value: 43 / Key: lima, Value: 98 /

但是如果你想要一个排序的列表你最好使用结构体切片。

type name struct {
	key string
	value int
}

五、map类型切片的注意点

当我们想获取一个 map 类型的切片,我们必须使用两次 make() 函数,第一次分配切片,第二次分配 切片中每个 map 元素

示例:

package main
import "fmt"

func main() {
	// Version A:
	items := make([]map[int]int, 5)
	for i:= range items {
		items[i] = make(map[int]int, 1)
		items[i][1] = 2
	}
	fmt.Printf("Version A: Value of items: %v\n", items)

	// Version B: NOT GOOD!
	items2 := make([]map[int]int, 5)
	for _, item := range items2 {
		item = make(map[int]int, 1) // item is only a copy of the slice element.
		item[1] = 2 // This 'item' will be lost on the next iteration.
	}
	fmt.Printf("Version B: Value of items: %v\n", items2)
}

输出:

Version A: Value of items: [map[1:2] map[1:2] map[1:2] map[1:2] map[1:2]]
Version B: Value of items: [map[] map[] map[] map[] map[]]

需要注意的是,应当像 A 版本那样通过索引使用切片的 map 元素。在 B 版本中获得的项只是 map 值的一个拷贝而已,所以真正的 map 元素没有得到初始化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值