在Go中解码JSON会改变对象类型吗?

huangapple go评论85阅读模式
英文:

JSON decoding in Go changes the object type?

问题

我正在尝试构建一个可以从JSON文件中读取多种不同类型对象的库(实际库从couchdb中提取对象,但为了演示目的,它从json中加载对象)。

我的库不知道正在加载的具体对象类型,因此下面的"CreateObject()"调用(在实际代码中由接口满足)。

我遇到的问题是,当我尝试将CreateObject()调用创建的对象强制转换回我的具体类型(在示例中为MyType)时,出现了恐慌错误:

panic: interface conversion: interface is map[string]interface {}, not main.MyType

我想知道我在这里做错了什么,或者是否有其他更符合Go语言风格的方法来解决这个问题。如果我在Java中做这个,我会使用泛型,并且期望它很简单。

请注意,如果我注释掉json.NewDecoder...这一行,那么代码就可以正常工作(输出一个空行,如预期)。这意味着在Decode操作中发生了一些问题。

以下是可运行的示例代码:

package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

type MyType struct {
	Name string `json:"name"`
	Age  int32  `json:"age"`
}

func CreateObject() interface{} {
	return MyType{}
}

func LoadJsonData() interface{} {
	obj := CreateObject()
	jsonStr := `{"name":"Person", "age":30}`
	json.NewDecoder(strings.NewReader(jsonStr)).Decode(&obj)

	return obj
}

func main() {

	obj := LoadJsonData()

    // 这段代码可以正常工作
	// y := obj.(map[string]interface{})
	// fmt.Println(y["name"])
	
    // 这段代码导致恐慌错误
    x := obj.(MyType)
   	fmt.Println(x.Name)
}
英文:

I am trying to build a library that can read multiple different types of objects out of JSON files (the actual library pulls them out of couchdb, but for the purposes of this it's loading them from json).

My library doesn't know anything about the concrete type of object being loaded, hence the "CreateObject()" call below (which is satisfied by an interface in the real code).

I'm having a problem that when I try to cast the object created by the CreateObject() call back to my concrete type (MyType in the example) I'm getting a panic:

panic: interface conversion: interface is map[string]interface {}, not main.MyType

I'd like to know where I'm going wrong here, or whether there's another more go-like way I should be approaching this problem. If I was doing it in Java I'd be using generics and would expect it to be straightforward.

Note that if I comment out the json.NewDecoder... line then the code works (prints out a blank line, as expected). This implies something is happening in the Decode operation.

Runnable example follows:

package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

type MyType struct {
	Name string `json:"name"`
	Age  int32  `json:"age"`
}

func CreateObject() interface{} {
	return MyType{}
}

func LoadJsonData() interface{} {
	obj := CreateObject()
	jsonStr := `{"name":"Person", "age":30}`
	json.NewDecoder(strings.NewReader(jsonStr)).Decode(&obj)

	return obj
}

func main() {

	obj := LoadJsonData()

    // This works for some reason
	// y := obj.(map[string]interface{})
	// fmt.Println(y["name"])
	
    // This causes a panic
    x := obj.(MyType)
   	fmt.Println(x.Name)
}

<kbd>Playground</kbd>

答案1

得分: 3

你应该使用指针而不是结构体:

func CreateObject() interface{} {
    return &MyType{} // 这里
}

...

// 这会导致恐慌
x := obj.(*MyType) // 还有这里
fmt.Println(x.Name)

链接:http://play.golang.org/p/vJjaQlq_vh

如果你想了解更多,请参考以下讨论:https://stackoverflow.com/questions/31960996/golang-fails-to-parse-json-for-reflection-created-object/31962240

英文:

You should use pointer instead of struct:

func CreateObject() interface{} {
    return &amp;MyType{} // here
}

...

// This causes a panic
x := obj.(*MyType) // and there
fmt.Println(x.Name)

Enjoy: http://play.golang.org/p/vJjaQlq_vh

If you want to read more about it, consider the following thread: https://stackoverflow.com/questions/31960996/golang-fails-to-parse-json-for-reflection-created-object/31962240

huangapple
  • 本文由 发表于 2015年8月19日 21:02:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/32096306.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定