英文:
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:
Unmarshal
gets a place to store the datav
with typeinterface{}
Unmarshal
detects a map encoded as JSONUnmarshal
sees 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:
Unmarshal
gets a place to store the datav
with typestruct main.J
Unmarshal
detects a map encoded as JSONUnmarshal
sees that the target type isstruct main.J
and 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
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论