为了账号安全,请及时绑定邮箱和手机立即绑定

关于接口分配

关于接口分配

Go
胡子哥哥 2023-07-26 16:42:08
当将结构体指针分配给接口时,为什么 Go 不认为这是类型不匹配错误?package mainimport "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”处的错误
查看完整描述

3 回答

?
桃花长相依

TA贡献1860条经验 获得超8个赞

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"]

}


查看完整回答
反对 回复 2023-07-26
?
ABOUTYOU

TA贡献1812条经验 获得超5个赞

会出现错误,因为a(*main.XYZ)的类型没有实现接口ABC

错误的。*main.XYZ实现ABC(否则abc = xyz会在编译时失败,尝试将方法重命名bc例如),但该变量a保存一个nil指针(类型为*XYZ)。由于该方法具有值接收器,因此要调用该方法,必须取消XYZ.a()引用类型的指针值。*XYZ但是nil指针不指向任何内容,它不能被取消引用,尝试这样做会导致运行时恐慌,就像您所经历的那样。

如果您xyz从一开始就使用非nil指针进行初始化,那么它会起作用:

var xyz *XYZ = new(XYZ)

在Go Playground上尝试一下。

另请注意,如果XYZ.a()XYZ.b()会有指针接收器,那么如果xyznil

func (xyz *XYZ) a() string {

    return "XYZ"

}


func (xyz *XYZ) b() int {

    return 123

}


func main() {

    var xyz *XYZ

    // ...

在Go Playground上尝试一下。这样做的原因是因为如果接收者是指针,则nil不必取消引用指针即可调用带有指针接收者的方法,因此不会发生运行时恐慌。当然,如果在方法中您引用XZY.aaXYZ.bb字段,那将是运行时恐慌,但您当前的方法实现不会这样做,所以它可以工作。



查看完整回答
反对 回复 2023-07-26
?
四季花海

TA贡献1811条经验 获得超5个赞

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



查看完整回答
反对 回复 2023-07-26
  • 3 回答
  • 0 关注
  • 159 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信