关于接口分配

当将结构体指针分配给接口时,为什么 Go 不认为这是类型不匹配错误?


package main


import "fmt"


type ABC interface {

    a() string

    b() int

}


type XYZ struct {

    aa string

    bb int

}


func (xyz XYZ) a() string {

    return "XYZ"

}


func (xyz XYZ) b() int {

    return 123

}


func main() {

    var xyz *XYZ

    var abc ABC = xyz // type of abc is *main.XYZ,I think that Golang can find this error here, but why not?


    fmt.Printf("%T\n", abc)


    a, ret := abc.(*XYZ)

    fmt.Println(a, ret) // type of a is *main.XYZ


    fmt.Println(a.a()) // will occur a error, because the type of a(*main.XYZ) not implements the interface ABC

}


我想知道为什么 Go 不认为这是“var abc ABC = xyz”处的错误


胡子哥哥
浏览 161回答 3
3回答

桃花长相依

XYZ 确实实现了 ABC。这与如何确定方法集有关(添加重点):类型可以具有与其关联的方法集。接口类型的方法集就是它的接口。任何其他类型 T 的方法集由接收者类型 T 声明的所有方法组成。对应指针类型 *T 的方法集是接收者 *T 或 T 声明的所有方法的集合(即还包含接收者类型 T 声明的方法)。集 T)。方法集决定接口是否实现:接口类型指定称为其接口的方法集。接口类型的变量可以存储任何类型的值,其方法集是接口的任何超集。这样的类型被称为实现接口。当调用 时*XYZ.a(),Go 编译器总是可以自动解引用指针来获取值接收者。这样做没有任何缺点,因为接收者无法修改(就调用者而言)。当且仅当该值是可寻址时,反逻辑才成立:type T struct {}func (*T) M()func main() {    var t T    t.M() // ok; t is addressable and the compiler rewrites this to (*t).M()    var m map[string]T    m["x"].M() // error: cannot take the address of m["x"]}

ABOUTYOU

会出现错误,因为a(*main.XYZ)的类型没有实现接口ABC错误的。*main.XYZ实现ABC(否则abc = xyz会在编译时失败,尝试将方法重命名b为c例如),但该变量a保存一个nil指针(类型为*XYZ)。由于该方法具有值接收器,因此要调用该方法,必须取消XYZ.a()引用类型的指针值。*XYZ但是nil指针不指向任何内容,它不能被取消引用,尝试这样做会导致运行时恐慌,就像您所经历的那样。如果您xyz从一开始就使用非nil指针进行初始化,那么它会起作用:var xyz *XYZ = new(XYZ)在Go Playground上尝试一下。另请注意,如果XYZ.a()和XYZ.b()会有指针接收器,那么如果xyz是nil:func (xyz *XYZ) a() string {    return "XYZ"}func (xyz *XYZ) b() int {    return 123}func main() {    var xyz *XYZ    // ...在Go Playground上尝试一下。这样做的原因是因为如果接收者是指针,则nil不必取消引用指针即可调用带有指针接收者的方法,因此不会发生运行时恐慌。当然,如果在方法中您引用XZY.aa或XYZ.bb字段,那将是运行时恐慌,但您当前的方法实现不会这样做,所以它可以工作。

四季花海

当我在值上调用方法时(不是指针,是实现接口的结构的方法,并且方法的接收者是指针)。Golang会创建一个新对象,并从原始struct值中复制值,然后,iface.data将指向新对象,现在,当我们将新对象的指针传递给方法时,它可以被修改,但是这个操作不会改变原始结构体值,这没有任何用处,因此,当我们将结构体值分配给接口(指针接收者)时,Golang会发生错误
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go