gpt4 book ai didi

json - 如果 map 是引用类型,为什么 json.Unmarshal 需要指向 map 的指针?

转载 作者:IT王子 更新时间:2023-10-29 00:49:10 25 4
gpt4 key购买 nike

我在使用 json.Unmarshal 时遇到了以下怪癖。运行以下代码时,出现错误 json: Unmarshal(non-pointer map[string]string)

func main() {
m := make(map[string]string)
data := `{"foo": "bar"}`
err := json.Unmarshal([]byte(data), m)
if err != nil {
log.Fatal(err)
}

fmt.Println(m)
}

Playground

查看 documentation对于 json.Unmarshal,似乎没有迹象表明需要指针。我能找到的最接近的是以下行

Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v.

关于 Unmarshal 遵循的映射协议(protocol)的行同样不清楚,因为它没有引用指针。

To unmarshal a JSON object into a map, Unmarshal first establishes a map to use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal reuses the existing map, keeping existing entries. Unmarshal then stores key-value pairs from the JSON object into the map. The map's key type must either be a string, an integer, or implement encoding.TextUnmarshaler.

为什么我必须将指针传递给 json.Unmarshal,尤其是当映射已经是引用类型时?我知道如果我将一个映射传递给一个函数,并将数据添加到映射中,映射的基础数据将被更改(请参阅 the following playground example ),这意味着如果我将指针传递给 map 。有人可以解决这个问题吗?

最佳答案

如文档中所述:

Unmarshal uses the inverse of the encodings that Marshal uses, allocating maps, slices, and pointers as necessary, with ...

Unmarshal 可以分配变量(映射、 slice 等)。如果我们将 map 而不是 pointer 传递给 map,那么新分配的 map 将不可见给来电者。以下示例 ( Go Playground) 对此进行了演示:

package main

import (
"fmt"
)

func mapFunc(m map[string]interface{}) {
m = make(map[string]interface{})
m["abc"] = "123"
}

func mapPtrFunc(mp *map[string]interface{}) {
m := make(map[string]interface{})
m["abc"] = "123"

*mp = m
}

func main() {
var m1, m2 map[string]interface{}
mapFunc(m1)
mapPtrFunc(&m2)

fmt.Printf("%+v, %+v\n", m1, m2)
}

其中的输出是:

map[], map[abc:123]

如果需求说一个函数/方法可以在必要时分配一个变量并且新分配的变量需要对调用者可见,解决方案将是:(a)变量必须在函数的返回 语句 (b) 可以将变量分配给函数/方法参数。因为在 goeverything 都是按值传递的,所以在 (b) 的情况下,参数必须是一个指针。下图说明了上述示例中发生的情况:

Illustration of variable allocation

  1. 首先,映射m1m2都指向nil
  2. 调用mapFunc会将m1指向的值复制到m,结果m也将指向 map 。
  3. 如果在 (1) 中映射已经分配,​​则在 (2) 中 底层映射数据结构m1 指向的地址(不是地址m1) 将被复制到 m。在这种情况下,m1m 都指向相同的 map 数据结构,因此通过 m1 修改 map 项将对 m可见
  4. mapFunc 函数中,分配新 map 并将其赋值给m。无法将其分配给 m1

在指针的情况下:

  1. 当调用mapPtrFunc时,m2的地址会被复制到mp
  2. mapPtrFunc中,新 map 被分配并分配给*mp(不是mp)。由于 mp 是指向 m2 的指针,将新映射分配给 *mp 将更改 m2 指向的值。注意mp的值是不变的,即m2的地址。

关于json - 如果 map 是引用类型,为什么 json.Unmarshal 需要指向 map 的指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45122496/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com