下面这段代码输出什么?为什么?
package main
import "fmt"
type People interface {
Show()
}
type Student struct{}
func (stu *Student) Show() {
}
func main() {
var s *Student
if s == nil {
fmt.Println("s is nil")
} else {
fmt.Println("s is not nil")
}
var p People = s
if p == nil {
fmt.Println("p is nil")
} else {
fmt.Println("p is not nil")
}
}
s is nil
p is not nil
记住一点,当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil。
代码解析:
1. 变量 s 的判断
var s *Student声明了一个*Student类型的指针变量s,默认值为nil- 直接判断
s == nil为true,输出s is nil
2. 变量 p 的判断
var p People = s将s(值为nil的指针)赋值给接口类型People的变量p- Go 接口的底层结构:接口变量
p包含两个字段:动态类型(*Student):存储赋值给接口的具体类型动态值(nil):存储具体类型的值
- 接口判空规则:只有当接口的
动态类型和动态值同时为nil时,接口变量才等于nil- 本例中,
p的动态类型是*Student(非nil),动态值是nil,因此p == nil为false,输出p is not nil
- 本例中,
关键结论
- 指针判空:
var s *T的默认值是nil - 接口判空:
- 如果直接将
nil赋给接口(如var p People = nil),则接口的动态类型和动态值均为nil,此时p == nil为true - 如果通过具体类型的
nil指针赋给接口(如var p People = s),则接口的动态类型会被记录为具体类型(非nil),即使值为nil,接口变量也不等于nil
- 如果直接将
总结:
我们分配给变量 p 的值明明是 nil,然而 p 却不是 nil。记住一点,当且仅当动态值和动态类型都为 nil 时,接口类型值才为 nil。上面的代码中,给变量 p 赋值之后,p 的动态值是 nil,但是动态类型却是 *Student,是一个 nil 指针,所以 p == nil 为 false。