解组为接口类型

Unmarshall into an interface type

我希望下面的代码打印一个结构类型 J 的对象,但是它打印了一个 map[string]interface{} 类型的地图对象。我能感觉到它为什么会这样,但是当我 运行、reflect.ValueOf(i).Kind() 时,它 returns Struct,所以它有点给了我印象是 Unmarshal 方法应该 return 键入 J 而不是地图。谁能赐教一下?

type J struct {
    Text string
}

func main() {
    j := J{}
    var i interface{} = j

    js := "{\"Text\": \"lala\"}"


    json.Unmarshal([]byte(js), &i)

    fmt.Printf("%#v", i)

}

您传递给 Unmarshal 的类型不是 *J,您传递的是 *interface{}

json 包反映它接收到的指针的类型时,它会看到 interface{},因此它会使用包的默认类型解组为

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

几乎没有理由使用指向接口的指针。如果您发现自己使用了一个指向接口的指针,并且您不知道 确切地 为什么,那么这可能是一个错误。如果您想解组为 J,则直接将其传入。如果您需要将其分配给中间接口,请确保使用指向原始值的指针,而不是指向其接口的指针。

http://play.golang.org/p/uJDFKfSIxN

j := J{}
var i interface{} = &j

js := "{\"Text\": \"lala\"}"

json.Unmarshal([]byte(js), i)

fmt.Printf("%#v", i)

这是预期的行为:不是给 json.Unmarshal 一个指向内存中正确类型位置的指针,而是给它一个指向内存中类型为 interface{} 的位置的指针。它基本上可以在 JSON 定义的类型下存储任何内容,所以它就是这样做的。

这样看:

  1. Unmarshal 获取存储类型为 interface{}
  2. 的数据 v 的位置
  3. Unmarshal 检测到编码为 JSON
  4. 的地图
  5. Unmarshal 看到目标类型是 interface{} 类型,从中创建一个 go map 并将其存储在 v

如果您给它一个不同于 interface{} 的类型,则该过程将如下所示:

  1. Unmarshal 获取存储类型为 struct main.J
  2. 的数据 v 的位置
  3. Unmarshal 检测到编码为 JSON
  4. 的地图
  5. Unmarshal看到目标类型是struct main.J,开始递归拟合数据到
  6. 类型

要点是,初始赋值

var i interface{} = j

json.Unmarshal完全忽略了。