[TOC]
## 三、Map
### (1) Map的Value賦值
> 下面代碼編譯會出現什么結果?
> test7.go
```go
package main
import "fmt"
type Student struct {
Name string
}
var list map[string]Student
func main() {
list = make(map[string]Student)
student := Student{"Aceld"}
list["student"] = student
list["student"].Name = "LDB"
fmt.Println(list["student"])
}
```
**結果**
編譯失敗,`./test7.go:18:23: cannot assign to struct field list["student"].Name in map`
**分析**
`map[string]Student` 的value是一個Student結構值,所以當`list["student"] = student`,是一個值拷貝過程。而`list["student"]`則是一個值引用。那么值引用的特點是`只讀`。所以對`list["student"].Name = "LDB"`的修改是不允許的。
**方法一:**
```go
package main
import "fmt"
type Student struct {
Name string
}
var list map[string]Student
func main() {
list = make(map[string]Student)
student := Student{"Aceld"}
list["student"] = student
//list["student"].Name = "LDB"
/*
方法1:
*/
tmpStudent := list["student"]
tmpStudent.Name = "LDB"
list["student"] = tmpStudent
fmt.Println(list["student"])
}
```
其中
```go
/*
方法1:
*/
tmpStudent := list["student"]
tmpStudent.Name = "LDB"
list["student"] = tmpStudent
```
是先做一次值拷貝,做出一個`tmpStudent副本`,然后修改該副本,然后再次發生一次值拷貝復制回去,`list["student"] = tmpStudent`,但是這種會在整體過程中發生2次結構體值拷貝,性能很差。
**方法二**:
```go
package main
import "fmt"
type Student struct {
Name string
}
var list map[string]*Student
func main() {
list = make(map[string]*Student)
student := Student{"Aceld"}
list["student"] = &student
list["student"].Name = "LDB"
fmt.Println(list["student"])
}
```
我們將map的類型的value由Student值,改成Student指針。
```go
var list map[string]*Student
```
這樣,我們實際上每次修改的都是指針所指向的Student空間,指針本身是常指針,不能修改,`只讀`屬性,但是指向的Student是可以隨便修改的,而且這里并不需要值拷貝。只是一個指針的賦值。
### (2) map的遍歷賦值
---
> 以下代碼有什么問題,說明原因
> test8.go
```go
package main
import (
"fmt"
)
type student struct {
Name string
Age int
}
func main() {
//定義map
m := make(map[string]*student)
//定義student數組
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
//將數組依次添加到map中
for _, stu := range stus {
m[stu.Name] = &stu
}
//打印map
for k,v := range m {
fmt.Println(k ,"=>", v.Name)
}
}
```
**結果**
遍歷結果出現錯誤,輸出結果為
```bash
zhou => wang
li => wang
wang => wang
```
map中的3個key均指向數組中最后一個結構體。
**分析**
foreach中,stu是結構體的一個拷貝副本,所以`m[stu.Name]=&stu`實際上一致指向同一個指針, 最終該指針的值為遍歷的最后一個`struct的值拷貝`。

**正確寫法**
```go
package main
import (
"fmt"
)
type student struct {
Name string
Age int
}
func main() {
//定義map
m := make(map[string]*student)
//定義student數組
stus := []student{
{Name: "zhou", Age: 24},
{Name: "li", Age: 23},
{Name: "wang", Age: 22},
}
// 遍歷結構體數組,依次賦值給map
for i := 0; i < len(stus); i++ {
m[stus[i].Name] = &stus[i]
}
//打印map
for k,v := range m {
fmt.Println(k ,"=>", v.Name)
}
}
```

**運行結果**
```bash
zhou => zhou
li => li
wang => wang
```
- 封面
- 第一篇:Golang修養必經之路
- 1、最常用的調試 golang 的 bug 以及性能問題的實踐方法?
- 2、Golang的協程調度器原理及GMP設計思想?
- 3、Golang中逃逸現象, 變量“何時棧?何時堆?”
- 4、Golang中make與new有何區別?
- 5、Golang三色標記+混合寫屏障GC模式全分析
- 6、面向對象的編程思維理解interface
- 7、Golang中的Defer必掌握的7知識點
- 8、精通Golang項目依賴Go modules
- 9、一站式精通Golang內存管理
- 第二篇:Golang面試之路
- 1、數據定義
- 2、數組和切片
- 3、Map
- 4、interface
- 5、channel
- 6、WaitGroup
- 第三篇、Golang編程設計與通用之路
- 1、流?I/O操作?阻塞?epoll?
- 2、分布式從ACID、CAP、BASE的理論推進
- 3、對于操作系統而言進程、線程以及Goroutine協程的區別
- 4、Go是否可以無限go? 如何限定數量?
- 5、單點Server的N種并發模型匯總
- 6、TCP中TIME_WAIT狀態意義詳解
- 7、動態保活Worker工作池設計