nil,空接口,空结构体有什么区别
Laiyong Wang Lv6

我的总结

nil是空,并不一定是空指针
nil是六种类型的零值
每种类型的nil是不同的,不能比较

空结构体

是go中特殊的类型
空结构体的值不是nill
指针也不是nill,但是都是相同(zerobase)

空接口
空接口的值也不一定是nil
类型为nil,值为nil才是nil接口

AI根据我的总结使用代码解释并完善

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

import (
"fmt"
"unsafe"
)

func main() {
// 示例1: 不同类型nil的比较
var p *int
var s []int
fmt.Println(p == nil) // true
fmt.Println(s == nil) // true
// fmt.Println(p == s) // 编译错误:类型不匹配

// 示例2: 空结构体
var e1 struct{}
var e2 struct{}
fmt.Printf("size: %d\n", unsafe.Sizeof(e1)) // 0
fmt.Printf("addr: %p %p\n", &e1, &e2) // 相同地址(zerobase)
fmt.Println(&e1 == &e2) // true

// 示例3: 空接口判断
var a interface{} = (*int)(nil)
fmt.Println(a == nil) // false(类型为*int,值为nil)

var b interface{} = nil
fmt.Println(b == nil) // true(类型和值均为nil)

// 示例4: 接口变量赋值
var c *int
var d interface{} = c
fmt.Println(d == nil) // false(类型为*int,值为nil)
}

完整解释:

1. nil的本质
• 是6种类型的零值:指针、接口、切片、map、channel、函数
• 不同类型的nil不相等,内存表示不同

1
2
3
4
var p *int
var s []int
fmt.Printf("%p\n", p) // 0x0
fmt.Printf("%#v\n", s) // []int(nil)

2. 空结构体 struct{}
• 实例不占内存(size=0)
• 所有实例共享同一内存地址(zerobase)
• 常用于信号传递(channel信号)、实现Set

1
2
3
4
5
6
7
8
9
// 作为方法接收器
type MyType struct{}
func (t MyType) Print() {
fmt.Println("不需要状态")
}

// 实现Set
set := make(map[string]struct{})
set["key"] = struct{}{}

3. 空接口 interface{}
• 由类型指针和数据指针组成(runtime.eface)
• 双重nil才等于nil

1
2
3
4
5
6
7
8
9
// 接口内部结构示意
type eface struct {
_type *_type
data unsafe.Pointer
}

var a interface{} = (*int)(nil)
// _type指向int类型元数据
// data = 0x0

关键区别表格

特性 nil struct{} interface{}
内存占用 类型决定 0字节 16字节(2指针)
相等性 同类型相等 地址始终相同 类型+值双nil才相等
典型用途 表示缺失值 占位符/信号 泛型容器
指针比较 0x0 zerobase地址 依赖存储内容
$li-margin-bottom = 0.8rem $post-tool-button-width = 2.5rem .post-tools-container { padding-top var(--component-gap) .post-tools-list { li { margin-bottom $li-margin-bottom &:last-child { margin-bottom 0 } } li.tools-item { position relative box-sizing border-box width $post-tool-button-width height $post-tool-button-width color var(--text-color-3) font-size 1.2rem background var(--background-color-1) border-radius 50% box-shadow 2px 2px 5px var(--shadow-color) cursor pointer &:hover { box-shadow 2px 2px 8px var(--shadow-hover-color) } i { color var(--text-color-3) } &:hover { color var(--background-color-1) background var(--primary-color) i { color var(--background-color-1) !important } } &.toggle-show-toc { display none } &.go-to-comments { .post-comments-count { position absolute top 0 right -1rem display none align-items center justify-content center box-sizing border-box min-width 1.1rem height 1.1rem padding 0 0.2rem color var(--badge-color) font-size 12px background var(--badge-background-color) border-radius 0.4rem +keep-tablet() { display none !important } } } } li.status-item { width $post-tool-button-width height $post-tool-button-width color var(--text-color-3) font-size 1.6rem cursor pointer &.post-lock { cursor default .fa-lock-open { display none color var(--keep-success-color) } &.decrypt { cursor pointer .fa-lock-open { display block } .fa-lock { display none } } } } } }