自学内容网 自学内容网

go里面 interface 是否为nil


代码片段


type AAA interface {
GetName() string
}

type aaa struct {
name string
}

func (a *aaa) GetName() string {
fmt.Println("进来了")
return a.name
}

func newAAA() any {
var a *aaa = nil

return a
}

func demo() {
// 踩坑的一天

anyA := newAAA()
if anyA == nil {
fmt.Println("anyA 是 nil")
} else {
fmt.Println("anyA 不是 nil")
}

// =========================================================

A, Ok := anyA.(AAA)
if Ok {
fmt.Println("anyA 是 AAA")
} else {
fmt.Println("anyA 不是 AAA")
}
if A == nil {
fmt.Println("A 是 nil")
} else {
fmt.Println("A 不是 nil")
A.GetName()
}
}

总结:

代码中,newAAA 函数返回了一个 *aaa 类型的 nil 指针,但是由于它是作为 any 类型(即 interface{})返回的,所以尽管它内部的值是 nilanyA 本身并不是 nil。这是因为接口在 Go 中是由动态类型和动态值组成的,当仅动态值为 nil 时,接口本身并不会被认为是 nil

demo 函数中,这种情况的处理如下:

  1. 当检查 anyA == nil 时,结果为 false,因为 anyA 内部包含的动态类型是 *aaa,并不是无类型的 nil。所以会打印 "anyA 不是 nil"

  2. 接下来的类型断言 A, Ok := anyA.(AAA) 检查 anyA 是否实现了 AAA 接口。由于 *aaa 类型实现了 AAA 接口(因为 *aaa 有一个定义的 GetName 方法),类型断言会成功,变量 Oktrue。所以会打印 "anyA 是 AAA"

  3. 尽管 A 是从一个为 nil*aaa 类型变量断言出的 AAA 接口类型,A 本身也并不会是 nil,因为它携带了 *aaa 的类型信息。所以,if A == nil 的检查结果会是 false。会打印 "A 不是 nil",然后执行 A.GetName()

  4. 在调用 A.GetName() 时,会发生运行时错误,因为实际上 Anil,当试图通过 nil 指针调用一个方法。在这里的 GetName 方法的实现中,如果接收器是 nil,就会引发 panic,因为在方法内部试图访问 a.name,这需要对 nil 指针进行解引用操作。

所以,执行 demo() 函数的结果将是:

anyA 不是 nil
anyA 是 AAA
A 不是 nil
进来了

紧接着的是程序会因为 nil 的解引用崩溃。

对于 demo 函数,它展示了如何检查一个变量是否实现了某个接口,然而,关于接收器为 nil 的方法调用,必须特别小心。在 Go 中,允许 nil 接收器的方法调用,只要方法内部正确处理 nil。但在很多情况下,这可能不是预期的行为,按照正常的思路一般都会认为接收器不会是nil,这就是需要注意的点。

一个更健壮的做法是在设计接口和方法时避免这种状况,例如不返回包含 nil 的接口类型,或者在方法内部检查接收器是否为 nil。这样,调用者就不需要编写复杂的 nil 检查逻辑,代码的安全性和可读性都会提高。


一点点笔记,以便以后翻阅。


原文地址:https://blog.csdn.net/qq_44111597/article/details/144056569

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!