Golang接口{}类型的误解 [英] Golang interface{} type misunderstanding
问题描述
当使用 因为一段代码胜过千言万语,下面是一个例子: 输出: 小读数后面解释了一些, 从 要将JSON解组为接口值,Unmarshal会将 如果我像这样传递一个指向测试函数的指针,它可以工作: 以下输出: 酷,数据已解组,所有,现在在第二个片段中,当调用 因此,在所有逻辑中,如果我在调用<$ c时将接口{}
作为函数参数类型时,在给出非指针类型并使用 json时,我在Go中遇到了一个bug 。
它应该再次与
package main
import(
encoding / json
fmt
)
func test(i interface {}){
j:= [] byte(`{foo:bar}`)
fmt.Printf(%T \ n,i)
fmt.Printf(%T \ n,& i)
json.Unmarshal(j,& i)
fmt.Printf( %T \ n,i)
}
类型测试结构{
Foo字符串
}
func main(){
test(Test {})
}
main.Test
* interface {}
map [string] interface {}
json.Unmarshal
将我的结构转换为映射[string] interface {}
oO ...
interface {}
本身就是一种类型,而不是某种无类型的容器,它解释了 * interface {}
,事实上
json.Unmarshal
无法获得初始类型,并返回了一个 map [string] interface {}
..
Unmarshal
文档:
中的一个存储在接口值中:
[...]
func test(i interface {}){
j:= [] byte(`{foo:bar}`)
fmt.Printf(%T \ n,i)
fmt.Printf(%T \ n,& i)
json.Unmarshal(j,i)
fmt.Printf(%T \ n),i)
fmt.Println(i)
}
func main(){
test(& Test {})
}
* main.Test
* interface {}
* main.Test
& {bar}
Unmarshal 时,我移除了
&
。因为我在 i
中有一个 * Test
,所以没有用。
&
放回到 i
$ c> Unmarshal i
的类型混淆。但是不是。
如果我运行:
func test(i接口{}){
j:= []字节(`{foo:bar}`)
fmt.Printf(%T \ n,i)
fmt .Printf(%T \ n,& i)
json.Unmarshal(j,& i)
fmt.Printf(%T \ n,i)
$ f
func main(){
test(& Test {})
}
$ c
它仍然有效:
* main.Test
* interface {}
* main.Test
& {bar}
现在我不在google搜索查询中。 正确的方案 >
interface {}
是任何值和任何类型的包装。一个接口示意性地包装了一个(value; type)
对,一个具体的值及其类型。更多细节:反思的法则#接口的表示。
json.Unmarshal()
已经取得类型 interface { }
:
$ b
func Unmarshal(data [] byte,v interface {})错误
因此,如果您已经有 当 当 总而言之,避免使用指向接口的指针。而是将指针放入接口(接口值应该包装指针)。当你已经有一个 I got a bug in Go when using an Because a piece of code is worth a thousand words, here is an example: Which outputs: Little readings later explains some of it, From To unmarshal JSON into an interface value, Unmarshal stores one of
these in the interface value:
[...] And if I pass a pointer to the test function like so, it works: Which outputs: Cool, the data is unmarshalled and all, now in this second snippet I removed the So in all logic, if I put back the If I run: Well it still works: And now I'm out of google search queries. So if you already have an Also note that for any package to modify a value stored in an When When All in all, avoid using pointers to interfaces. Instead "put" pointers into the interfaces (the interface value should wrap the pointer). When you already have an 这篇关于Golang接口{}类型的误解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!界面{}
值( test()
函数的 i interface {}
参数,不要试图获取它的地址,只是还要注意,对于任何包来修改存储在 interface {}中的值 >,你需要传递一个指针给它。那么
i
应该是一个指针。因此,正确的方案是将 * Test
传递给 test()
,并在 test )
传递 i
到 json.Unmarshal()
(不需要它的地址) / b>
其他情况的解释
i
包含 * Test
并且您传递了& i
,它会工作,因为 json
package将简单地解引用 * interface {}
指针,并找到一个 interface {}
值,一个 * Test
值。它是一个指针,所以它很好:将JSON对象解组到指向 Test
值。
i
包含 Test
并且您传递& i
,同样的事情发生如上所示: * interface {}
被取消引用,所以它找到一个包含非指针的 interface {}
测试
。由于 json
包无法解组为非指针值,因此必须创建一个新值。并且由于传递给 json.Unmarshal()
函数的值的类型是 * interface {}
,它会告诉 json
package将数据解组为一个值为 interface {}
的值。这意味着 json
包可以自由选择使用哪种类型。默认情况下, json
包将JSON对象解组为 map [string] interface {}
值,这就是创建的并使用(并最终放入您传递的指针指向的值:& i
)。
全部在所有
接口{}
存储一个指针时,只需传递它即可。interface{}
as function parameter type, when given a non-pointer type, and using json.Unmarshal
with it.package main
import (
"encoding/json"
"fmt"
)
func test(i interface{}) {
j := []byte(`{ "foo": "bar" }`)
fmt.Printf("%T\n", i)
fmt.Printf("%T\n", &i)
json.Unmarshal(j, &i)
fmt.Printf("%T\n", i)
}
type Test struct {
Foo string
}
func main() {
test(Test{})
}
main.Test
*interface {}
map[string]interface {}
json.Unmarshal
turns my struct to a map[string]interface{}
oO...interface{}
is a type in itself, not some sort of typeless container, which explains the *interface{}
, and the fact that json.Unmarshal
could not get the initial type, and returned a map[string]interface{}
..Unmarshal
docs:
func test(i interface{}) {
j := []byte(`{ "foo": "bar" }`)
fmt.Printf("%T\n", i)
fmt.Printf("%T\n", &i)
json.Unmarshal(j, i)
fmt.Printf("%T\n", i)
fmt.Println(i)
}
func main() {
test(&Test{})
}
*main.Test
*interface {}
*main.Test
&{bar}
&
when calling Unmarshal
. Because I have a *Test
in i
, no use for it.&
to i
when calling Unmarshal
it should mess up with i
's type again. But no.func test(i interface{}) {
j := []byte(`{ "foo": "bar" }`)
fmt.Printf("%T\n", i)
fmt.Printf("%T\n", &i)
json.Unmarshal(j, &i)
fmt.Printf("%T\n", i)
fmt.Println(i)
}
func main() {
test(&Test{})
}
*main.Test
*interface {}
*main.Test
&{bar}
The right scenario
interface{}
is a wrapper for any value and of any type. An interface schematically wraps a (value; type)
pair, a concrete value and its type. More details on this: The Laws of Reflection #The representation of an interface.json.Unmarshal()
already takes the value of type interface{}
:func Unmarshal(data []byte, v interface{}) error
interface{}
value (the i interface{}
parameter of the test()
function), don't try to take its address, just pass it along as-is.interface{}
, you need to pass a pointer to it. So what should be in i
is a pointer. So the right scenario is to pass *Test
to test()
, and inside test()
pass i
to json.Unmarshal()
(without taking its address).Explanation of other scenarios
i
contains *Test
and you pass &i
, it will work because the json
package will simply dereference the *interface{}
pointer, and finds an interface{}
value, which wraps a *Test
value. It's a pointer, so it's all good: unmarshals the JSON object into the pointed Test
value.i
contains Test
and you pass &i
, same thing goes as above: *interface{}
is dereferenced, so it finds an interface{}
which contains a non-pointer: Test
. Since the json
package can't unmarshal into a non-pointer value, it has to create a new value. And since the passed value to the json.Unmarshal()
function is of type *interface{}
, it tells the json
package to unmarshal the data into a value of type interface{}
. This means the json
package is free to choose which type to use. And by default the json
package unmarshals JSON objects into map[string]interface{}
values, so that is what's created and used (and eventually put into the value pointed by the pointer you passed: &i
).All in all
interface{}
holding a pointer, just pass it along.