这里将自己学习Go及其区块链的一些笔记、积累分享一下,如果涉及到了文章、文字侵权,请联系我删除或调整。
1. 映射(map)
- 数组和切片中的元素都是通过整数形式的索引来访问的,这相当于在逻辑上建立了一种从整数索引到任意类型元素之间的对应关系。
- 映射则进一步突破了对索引的类型约束,将其定义为可用任意类型表示的键,而与之对应的被检索信息则被称为值,因此映射可被视作键值对的集合。
- 映射以散列表作为底层结构,用键的哈希作为值的索引,因此键无序且唯一。
2. 创建映射(map)
映射可以直接创建,也可以借助内置函数make创建。
- var players map[string]int // 关键字map后面的方括号内是键的类型,其后是值的类型
- var players = make(map[string]int) // make函数返回给定类型的对象
- players := map[string]int{"Cook": 32, "Bairstow": 27} // 声明的同时初始化
3. 在映射中添加元素
- 在映射中添加元素(新增、修改)或访问映射中已有的元素都是通过方括号,二者的区别在于方括号内的键是否已存在。
注:在go语言中,当访问一个map中不存在的key时,go会自动在map中创建这个key并将其初始化为零值。并不会像其他语言一样报“不存在对应key”的错误。详见4。
players := map[string]int{"Cook": 32, "Bairstow": 27}
players["Stokes"] = 26 // 添加新元素"Stokes": 26
players["Bairstow"] = 28 // 修改旧元素"Bairstow": 27的值为28
fmt.Println(players["Cook"]) // 32,读取旧元素"Cook": 32的值
players["Brain"]++ // 先添加新元素"Brain": 0,然后自增其值为1
4. 如何判断map中的key是否存在
- 直接从映射中根据键检索值,即便得到一个零值,也并不意味着真的存在这样的键值对,因为该键也有可能并不存在。为了判断键是否存在可以这样做:
- value, ok := players[key]
- ok为true,key存在,value为其值
- ok为false,key不存在,value为零值
5. 遍历映射map
- 可以通过包含range子句的for循环遍历映射中的元素
- for key, value := range players { fmt.Println(key, value) }
- 同时遍历键和值
- for key := range players { fmt.Println(key, players[key]) }
- 只遍历键,再因键取值
- for _, value := range players { fmt.Println(value) }
- 只遍历值,忽略键
- for key, value := range players { fmt.Println(key, value) }
5. 映射作为函数的参数永远都是浅拷贝,共享数据,即便增加元素也不会重新分配内存。
// var 映射 map[键类型]值类型
// 映射 := make(map[键类型]值类型)
//
// 映射作为函数的参数都只是浅拷贝,共享
// 数据,即便增加元素也不会重新分配内存
package main
import "fmt"
func foo(players map[string]int) {
players["Cook"]++
fmt.Println(" foo:", players)
}
func bar(players map[string]int) {
players["Brain"] = 30
fmt.Println(" bar:", players)
}
func main() {
players := make(map[string]int)
players["Cook"] = 32
players["Bairstow"] = 27
players["Stokes"] = 26
fmt.Println("main:", players)// map[Stokes:26 Cook:32 Bairstow:27]
foo(players) // map[Cook:33 Bairstow:27 Stokes:26]
fmt.Println("main:", players) // map[Cook:33 Bairstow:27 Stokes:26]
bar(players) // map[Brain:30 Cook:33 Bairstow:27 Stokes:26]
fmt.Println("main:", players)//map[Brain:30 Cook:33 Bairstow:27 Stokes:26]
}
6. 从映射中删除元素
- 从映射中删除元素可使用内置函数delete,其参数为映射和欲删除元素的键。
- delete(players, "Brain") // 删除players映射中键为"Brain"的元素
- 从映射中删除元素时若所指定的键并不存在,则什么也不会发生。
- 与切片不同,针对映射的任何结构性改变,无论是添加新元素还是删除原有的元素,都不会创建新的映射,而只是在原来映射的基础上进行修改。
7. 复制映射(映射的深拷贝)
- 内置函数copy只能复制切片不能复制映射。为了获得一个映射的完整副本,可先将其编码为JSON字符串,再将该字符串解码到目标映射中。
jb, err := json.Marshal(players) // players -编码-> jb
json.Unmarshal(jb, &copied) // jb -解码-> copied
注:目标映射和源映射的键和值的类型必须完全相同。
// 映射赋值只是浅拷贝,共享数据,
// 即便删除元素也不会重新分配内存
package main
import "fmt"
func main() {
players, copied := make(
map[string]int), make(
map[string]int)
players["Cook"] = 32
players["Bairstow"] = 27
players["Stokes"] = 26
copied = players // 赋值的方式的拷贝是浅拷贝,则copied,players均指向同
// 一段内存
copied["Brain"] = 30
fmt.Println(players, copied)
// map[Cook:32 Bairstow:27 Stokes:26 Brain:30] map[Cook:32 Bairsto
// w:27 Stokes:26 Brain:30]
copied["Cook"]++
fmt.Println(players, copied)
// map[Cook:33 Bairstow:27 Stokes:26 Brain:30] map[Cook:33 Bairstow:
// 27 Stokes:26 Brain:30]
delete(copied, "Brain")
fmt.Println(players, copied)
// map[Cook:33 Bairstow:27 Stokes:26] map[Stokes:26 Cook:33 Bairsto
// w:27]
}