Pointers 指向接口的指针与在解组JSON时持有指针的接口
请考虑以下结构和接口定义Pointers 指向接口的指针与在解组JSON时持有指针的接口,pointers,go,interface,unmarshalling,Pointers,Go,Interface,Unmarshalling,请考虑以下结构和接口定义 type Foo interface { Operate() } type Bar struct { A int } func (b Bar) Operate() { //... } 现在,如果我们尝试执行以下()操作: 我们得到以下输出: x: {A:0} err: json: cannot unmarshal object into Go value of type main.Foo 但是,通过将基础数据替换为struct类型,它不会
type Foo interface {
Operate()
}
type Bar struct {
A int
}
func (b Bar) Operate() {
//...
}
现在,如果我们尝试执行以下()操作:
我们得到以下输出:
x: {A:0}
err: json: cannot unmarshal object into Go value of type main.Foo
但是,通过将基础数据替换为struct类型,它不会有任何问题():
输出:
x: &{A:5}
err: %!s(<nil>)
x:&{A:5}
错误:%!s()
然而,这让我很困惑。在调用Unmarshall时,我们仍然传递一个指向x的指针,据我所知,它应该足以允许我们修改下面的条。毕竟,指针只是内存中的地址。如果我们要传递那个地址,我们应该可以修改它,不是吗?为什么第二个例子有效,但第一个却不行?为什么作为指针的结构会产生所有差异?不同行为的根源在于,如果
json
包必须创建一个新值,那么该值必须是具体类型,不能是(非具体)接口类型
让我们详细说明一下
首先,让我们检查第二个工作示例。类型为Foo
的变量x
包装类型为*Bar
的指针值。当您将&x
传递给json.Unmarshal()
时,json
包将获得一个*Foo
指针值。指向接口的指针!不应该使用,但它在那里。json
包将取消对指针的引用,并获得类型为*Bar
的包装值。由于这是一个非nil
指针,因此json
包可以并且将继续使用它进行解组。一切都好!json
包将修改所指向的值
在您的第一个示例中发生了什么
在第一个示例中,类型为Foo
的x
变量包装了一个非指针结构值不能修改包装在接口中的值。
这是什么意思?json
包将再次接收类型为*Foo
的值。然后它继续并取消引用它,并获得一个包装在接口中的条值。无法修改Foo
界面中的条
值。json
包“交付”结果的唯一方法是创建一个实现Foo
的新值,并将该值存储在最初传递的*Foo
指向的位置。但是不能创建Foo
的值,它是一种非具体的接口类型。所以解组返回一个错误
一些附录。您的第二个工作示例:
var x Foo = &Bar{}
err := json.Unmarshal([]byte("{\"a\": 5}"), &x)
fmt.Printf("x: %+v\nerr: %s\n", x, err)
这是可行的,因为我们“准备”了一个非nil
*条
值来解组,所以json
包本身不必创建值。我们已经为Foo
接口类型准备并传递了一个值(具体类型为*Bar
)
如果我们存储一个指向x
的“键入的”nil
,如下所示:
var x Foo = &Bar{}
x = (*Bar)(nil)
err := json.Unmarshal([]byte("{\"a\": 5}"), &x)
fmt.Printf("x: %+v\nerr: %s\n", x, err)
我们将返回相同的错误(在上尝试):
x:
错误:json:无法将对象解组为main.Foo类型的Go值
解释是一样的:json
包不能使用nil
指针将值解组到。它还需要创建一个非具体类型的值Foo
,但这是不可能的。只能创建具体类型的值。不同行为的根源在于,如果json
包必须创建新值,则该值必须是具体类型,不能是(非具体)接口类型
让我们详细说明一下
首先,让我们检查第二个工作示例。类型为Foo
的变量x
包装类型为*Bar
的指针值。当您将&x
传递给json.Unmarshal()
时,json
包将获得一个*Foo
指针值。指向接口的指针!不应该使用,但它在那里。json
包将取消对指针的引用,并获得类型为*Bar
的包装值。由于这是一个非nil
指针,因此json
包可以并且将继续使用它进行解组。一切都好!json
包将修改所指向的值
在您的第一个示例中发生了什么
在第一个示例中,类型为Foo
的x
变量包装了一个非指针结构值不能修改包装在接口中的值。
这是什么意思?json
包将再次接收类型为*Foo
的值。然后它继续并取消引用它,并获得一个包装在接口中的条值。无法修改Foo
界面中的条
值。json
包“交付”结果的唯一方法是创建一个实现Foo
的新值,并将该值存储在最初传递的*Foo
指向的位置。但是不能创建Foo
的值,它是一种非具体的接口类型。所以解组返回一个错误
一些附录。您的第二个工作示例:
var x Foo = &Bar{}
err := json.Unmarshal([]byte("{\"a\": 5}"), &x)
fmt.Printf("x: %+v\nerr: %s\n", x, err)
这是可行的,因为我们“准备”了一个非nil
*条
值来解组,所以json
包本身不必创建值。我们已经为Foo
接口类型准备并传递了一个值(具体类型为*Bar
)
如果我们存储一个指向x
的“键入的”nil
,如下所示:
var x Foo = &Bar{}
x = (*Bar)(nil)
err := json.Unmarshal([]byte("{\"a\": 5}"), &x)
fmt.Printf("x: %+v\nerr: %s\n", x, err)
我们将返回相同的错误(在上尝试):
x:
错误:json:无法将对象解组为main.Foo类型的Go值
解释是一样的:json
包不能使用nil
指针将值解组到。它还需要创建一个非具体类型的值
x: <nil>
err: json: cannot unmarshal object into Go value of type main.Foo