Go中struct嵌入interface调用方法一正常一panic的原因是什么
Go nil接收者与nil接口调用的差异解析
示例代码如下:
package main import "fmt" type TestInterface interface { Walk() } type A struct { } func (a *A) Walk() { fmt.Println("hello world") } type B struct { TestInterface } func main() { var a *A b := B{} a.Walk() // 不会panic,尽管a是nil b.Walk() // 会panic }
a.Walk()不panic的原因
- Go的方法本质是将接收者作为第一个入参的普通函数,
func (a *A) Walk()等价于普通函数定义func Walk(a *A) - 此处
a是*A类型的nil指针,调用a.Walk()时只是把nil作为入参传入Walk函数 - 该Walk实现没有对接收者
a做解引用、没有访问a的任意成员,因此不会触发panic。如果Walk方法内存在访问a字段的逻辑,依然会触发panic。
b.Walk()触发panic的原因
- B结构体嵌入的是
TestInterface接口类型,嵌入接口的方法会被提升为B的方法,但提升方法的本质是调用B内嵌入的接口字段的对应方法 - 代码中初始化
b := B{}时没有给嵌入的TestInterface字段赋值,该接口字段为nil接口 - Go的接口调用依赖接口存储的动态类型和动态值,nil接口不持有任何动态类型信息,无法找到要执行的Walk方法实现,因此调用时直接触发panic。
如果需要让b.Walk()正常运行,只需要在初始化时给嵌入的接口赋值即可,示例:
b := B{TestInterface: a} b.Walk() // 正常输出hello world
内容的提问来源于stack exchange,提问作者0xhacker
相关产品推荐
相关产品推荐

