顾乔芝士网

持续更新的前后端开发技术栈

golang map存储struct结构体常见的坑

map存储struct结构体常见的坑

1 使用指针作为方法的 receiver

package main
import (
"fmt"
)
type data struct {
		name string
}
type printer interface {
print()
}
// 这里不能使用指针
func (p *data) print() {
    fmt.Println("name: ", p.name)
}
/*
//解决方法一: 正确的语法, 不能使用指针
func (p data) print() {
fmt.Println("name: ", p.name)
}
*/
func main() {
    d1 := data{"one"}
    d1.print() // d1 变量可寻址,可直接调用指针 receiver 的方法
    /*
    var in printer = data{"two"}
    in.print() // Error: 类型不匹配
    */

    m := map[string]data{
    "x": data{"three"},
    }
    // 对于 map 存储struct的数据类型, 不能使用指针
    m["x"].print() //Error: m["x"] 是不可寻址的 // 变动频繁

    // 解决方法二:
    r := m["x"]
    r.print()
}
/*
cannot use data literal (type data) as type printer in assignment:
data does not implement printer (print method has pointer receiver)
cannot call pointer method on m["x"]
cannot take the address of m["x"]
只要值是可寻址的, 就可以在值上直接调用指针方法。即是对一个方法, 它的 receiver 是指针就足矣。
但不是所有值都是可寻址的, 比如 map 类型的元素、通过 interface 引用的变量:
*/

2 更新 map 字段的值

package main
type data struct {
    name string
}
func main() {
    m := map[string]data{
   		 "x": {"Tom"},
    }
    m["x"].name = "Jerry" // 无法直接更新 struct 的字段值
}
/*
cannot assign to struct field m[“x”].name in map
因为 map 中的元素是不可寻址的。需区分开的是,slice 的元素可寻址:
*/

更新 map 中 struct 元素的字段值, 有 2 个方法:

(1) 使用局部变量

package main
import (
    "fmt"
)
// 提取整个 struct 到局部变量中, 修改字段值后再整个赋值
type data struct {
    name string
}
func main() {
    m := map[string]data{
        "x": {"Tom"},
    }
    r := m["x"]
    r.name = "Jerry"
    m["x"] = r
    fmt.Println(m) // map[x:{Jerry}]
}

(2) 使用指向元素的 map 指针

package main
import (
    "fmt"
)
type data struct {
    name string
}
func main() {
    m := map[string]*data{
    "x": {"Tom"},
    }
    m["x"].name = "Jerry" // 直接修改 m["x"] 中的字段
    fmt.Println(m["x"]) // &{Jerry}
    /*
    // 但是要注意下边这种误用:
    m["z"].name = "what" // panic: runtime error: invalid memory address or nil pointer dereference
    fmt.Println(m["x"])
    */
}

综合: slice 与 map 存储 struct的区别:

package main
import (
    "fmt"
)
type data struct {
    name string
}
func main() {
    // 使用切片
    s := []data{{"Tom"}}
    s[0].name = "Jerry" // 切片可以直接修改, 但是 map 不能直接修改
    fmt.Println(s) // [{Jerry}]
}
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言