英文:
Unmarshall into an interface type
问题
我预期以下代码将打印出一个类型为struct J的对象,但实际上它打印出了一个类型为map[string]interface{}的映射对象。我可以理解为什么会这样,但是当我运行reflect.ValueOf(i).Kind()时,它返回的是Struct,所以我有点觉得Unmarshal方法应该返回类型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)
}
英文:
I expected below code to print an object of type struct J, however it prints a map object of type map[string]interface{}. I can feel why it acts like that, however when I run, reflect.ValueOf(i).Kind(), it returns Struct, so it kinda gives me the impression that Unmarshal method should return type J instead of a map. Could anyone enlighten me ?
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)
}
答案1
得分: 3
你传递给Unmarshal的类型不是*J,而是*interface{}。
当json包反射接收到的指针的类型时,它看到的是interface{},因此它会使用包的默认类型进行解组,这些类型包括:
bool,用于JSON布尔值float64,用于JSON数字string,用于JSON字符串[]interface{},用于JSON数组map[string]interface{},用于JSON对象nil,用于JSON null
几乎没有理由使用指向接口的指针。如果你发现自己使用指向接口的指针,并且不知道确切的原因,那么很可能是个错误。如果你想要解组到J,那么直接传递它即可。如果你需要将其赋值给一个中间接口,确保使用指向原始值的指针,而不是指向其接口的指针。
j := J{}
var i interface{} = &j
js := "{\"Text\": \"lala\"}"
json.Unmarshal([]byte(js), i)
fmt.Printf("%#v", i)
希望对你有帮助!
英文:
The type you're passing into Unmarshal is not *J, you're passing in an *interface{}.
When the json package reflects what the type is of the pointer it received, it sees interface{}, so it then uses the default types of the package to unmarshal into, which are
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
There is almost never a reason to use a pointer to an interface. If you find yourself using a pointer to an interface, and you don't know exactly why, then it's probably a mistake. If you want to unmarshal into J, then pass that in directly. If you need to assign that to an intermediary interface, make sure you use a pointer to the original value, not a pointer to its interface.
http://play.golang.org/p/uJDFKfSIxN
j := J{}
var i interface{} = &j
js := "{\"Text\": \"lala\"}"
json.Unmarshal([]byte(js), i)
fmt.Printf("%#v", i)
答案2
得分: 2
这是预期的行为:json.Unmarshal不是给一个指向正确类型的内存位置的指针,而是给了一个指向类型为interface{}的内存位置的指针。它可以在这个位置存储任何类型的数据,根据JSON定义的类型进行存储。
可以这样理解:
Unmarshal获取一个类型为interface{}的数据v的存储位置。Unmarshal检测到一个以JSON编码的映射。Unmarshal发现目标类型是interface{}类型,创建一个Go映射并将其存储在v中。
如果你给它一个不同于interface{}的类型,过程将如下所示:
Unmarshal获取一个类型为struct main.J的数据v的存储位置。Unmarshal检测到一个以JSON编码的映射。Unmarshal发现目标类型是struct main.J,并开始递归地将数据适配到该类型。
关键点在于,初始赋值
var i interface{} = j
在 json.Unmarshal 中完全被忽略。
英文:
This is expected behavior: instead of giving json.Unmarshal a pointer to a properly typed place in memory you give it a pointer to a place in memory with type interface{}. It can essentially store anything in there under the type the JSON defines, so it does just that.
See it like this:
Unmarshalgets a place to store the datavwith typeinterface{}Unmarshaldetects a map encoded as JSONUnmarshalsees that the target type is of typeinterface{}, creates a go map from it and stores it inv
If you would have given it a different type than interface{} the process would have looked like this:
Unmarshalgets a place to store the datavwith typestruct main.JUnmarshaldetects a map encoded as JSONUnmarshalsees that the target type isstruct main.Jand begins to recursively fit the data to the type
The main point is, that the initial assignment
var i interface{} = j
is completely ignored by json.Unmarshal.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论