true、false、nil 是预定义标识符而非常量,不能用于数组长度等需编译期常量的场景;nil 无类型,赋值或传参时须显式转换,如 (io.Reader)(nil);true/false 是无类型布尔值,const 块中为常量,单独使用为运行时值。

Go 里 true、false、nil 不是常量,是预定义标识符
它们不能像 const Pi = 3.14 那样被重新赋值或用在需要常量的上下文中(比如数组长度、case 值),但编译器对它们有特殊处理。本质是语言层面“硬编码”的值占位符,不是用户可定义的常量类型。
常见错误现象:const x = true 看似合法,但其实 true 在这里只是被当作一个无类型布尔字面量参与常量推导,并非引用某个内置常量;更典型的坑是试图把 nil 当作类型安全的常量传参——它没有类型,必须显式转换。
-
nil只能赋给指针、切片、映射、通道、函数、接口这六种类型,直接写var x = nil会报错:"use of untyped nil" -
true和false是无类型布尔值,可用于任何布尔上下文,但无法用unsafe.Sizeof(true)查大小(非常量) - 它们不归入
const块,也不出现在go doc builtin的常量列表里,只在语言规范中定义为 “predeclared identifiers”
什么时候必须显式类型转换才能用 nil
当函数参数、返回值、结构体字段或类型断言要求明确类型时,nil 无法自动匹配。Go 不做隐式类型推导,尤其在泛型或接口方法签名中容易暴露这个问题。
使用场景:写一个接受 io.Reader 的函数,想传 nil 表示空输入;或者初始化一个泛型切片变量,需指定底层类型才能赋 nil。
立即学习“go语言免费学习笔记(深入)”;
- 错误写法:
doSomething(nil)(如果doSomething参数是io.Reader,编译失败) - 正确写法:
doSomething((io.Reader)(nil))或doSomething((*bytes.Buffer)(nil)) - 泛型例子:
var s []T = nil合法;但var s = nil报错,因为缺少类型信息 - 结构体字段若为接口类型,
struct{ R io.Reader }{nil}合法;但struct{ R io.Reader }{R: nil}也需类型提示,否则报错
true/false 在 const 块里和单独用没区别?
有区别,但仅限于常量传播和类型推导行为。写在 const 块里的 true 会被当作“无类型布尔常量”,和其他字面量一样参与常量折叠;而单独使用的 true 在运行时就是布尔值,不参与编译期计算。
性能影响几乎为零,但兼容性上要注意:老版本 Go(const b = true 定义的值在反射中可能显示为未导出常量名,而直接用 true 则无此问题。
-
const Debug = true可用于构建 tag 条件编译://go:build Debug(虽然实际用的是 build tag,不是这个 const) - 但
const MaxRetries = 3; const EnableRetry = true这类组合,在生成文档或调试时更易读,本质仍是字面量 - 不要指望
const包裹能让true获得额外类型安全——它还是无类型的
为什么 nil 不能和 == 比较不同类型
因为 nil 本身无类型,而 == 要求左右操作数类型一致或可互相转换。两个不同类型的 nil(比如 (*int)(nil) 和 ([]byte)(nil))无法直接比较,编译器拒绝这种操作。
典型错误现象:if err == nil && data == nil 看似自然,但如果 data 是自定义类型别名且未实现 ==,就会报错;更隐蔽的是接口值与具体类型 nil 的混淆。
- 接口变量为
nil,表示其动态类型和值都为空;但(*MyType)(nil)是指针类型,和接口nil不等价 - 正确判空接口:
if v == nil合法;但if v == (*int)(nil)编译失败 - 安全做法:对可能为
nil的接口,用类型断言+判断,而不是直接比nil - 切片、映射、通道的
nil行为一致(长度为 0、遍历安全、可传给标准库函数),但指针和函数的nil解引用会 panic
nil 都暗含一个类型,漏掉它,编译器不会帮你猜。










