Skip to content

Go struct 类型的 map 结构体成员不能修改的问题

约 495 字大约 2 分钟

2025-03-19

问题描述

首先,我们先来看这样一段代码

package main
import (
    "fmt"
)
type Person struct {
    Name string `json:"name"`
    Age  int `json:"age"`
}
func main() {
    personTable := map[string]Person{
        "1": {Name: "张三", Age: 18},
        "2": {Name: "李四", Age: 20},
        "3": {Name: "王五", Age: 22},
    }
    personTable["1"].Age = 19
    fmt.Println(persionTable["1"].Age)
}

这段代码的输出结果是多少呢? 答案是: 编译都会不通过, 会收到这样一条报错信息:

问题产生的原因

关于golang中map的这种古怪的特性有这样几个观点:

  • map作为一个封装好的数据结构,由于它底层可能会由于 数据扩张而进行迁移 ,所以拒绝直接寻址,避免产生野指针;
  • map中的key在不存在的时候,赋值语句其实会进行新的k-v值的插入,所以拒绝直接寻址结构体内的字段,以防结构体不存在的时候 可能造成的错误;
  • 这可能和map的 并发不安全性相关

x = y 这种赋值的方式,你必须知道 x 的地址,然后才能把值 y 赋给 x。 但 go 中的 map 的 value 本身是不可寻址的,因为 map 的扩容的时候,可能要做 key/val pair迁移 value 本身地址是会改变的 不支持寻址的话又怎么能赋值呢

问题的解决

迂回方式一:整体更新map的value部分

上述代码修改为如下逻辑:

    pTmp := personTable["1"]
    pTmp.Age = 19
    personTable["1"] = pTmp

迂回方式二:把map的value部分定义为对应类型的指针类型

上述代码修改为:

    personTable := map[string]*Person{
        "1": {Name: "张三", Age: 18},
        "2": {Name: "李四", Age: 20},
        "3": {Name: "王五", Age: 22},
    }
    personTable["1"].Age = 19

## map的实现原理

参考博客: [Golang Map的实现原理](/article/itgspd1c/)

Released under the MIT License.