Go 从 0 到精通 · 第 02 课:变量、常量与基础数据类型
Go 从 0 到精通 · 第 02 课:变量、常量与基础数据类型
学习定位:这是整套 Go 教程的第 2 课。
前置要求:已经完成第 1 课,理解了package main、main()、go run、go build和go mod init。
本课目标:掌握变量与常量的声明方式,理解 Go 的零值、类型推断机制,并学会选择常见基础数据类型。
1. 本课你要解决的核心问题
这一课的重点不是“把语法背下来”,而是把下面几个关键问题真正搞明白:
- 变量到底是什么
- Go 为什么既有
var,又有:= - 零值是什么意思,为什么重要
- 常量和变量本质上有什么区别
int、float64、bool、string应该怎么选- 什么情况下会遇到类型问题
如果这一课学扎实,后面的条件、循环、函数、切片、结构体都会顺很多。
2. 什么是变量
先不要急着记语法,先从概念理解。
2.1 变量的本质
变量可以理解为:
一块有名字的内存空间,用来保存某种类型的数据。
例如:
- 你的名字可以保存在变量里
- 年龄可以保存在变量里
- 是否登录成功可以保存在变量里
- 商品价格也可以保存在变量里
在程序运行过程中,变量里的值通常是可以变化的。
比如:
- 一开始年龄是
18 - 后面可能变成
19
这就是“变量”的含义。
3. Go 中变量的几种声明方式
Go 的变量声明并不复杂,但它有几种常见写法。你不能只会一种,要知道每一种适合什么场景。
3.1 最完整写法:var 变量名 类型
1 | package main |
这段代码里:
name的类型是stringage的类型是int
即使你没有手动给它们赋值,它们也不会是“随机值”,而会有默认值。这个默认值在 Go 里叫:零值。
上面程序输出通常是:
1 |
|
第一行是空字符串,所以你看到的是空白。第二行是 0。
这种写法的特点是:
- 类型写得很清楚
- 适合强调变量类型
- 适合你暂时还不赋值的场景
3.2 声明时顺便赋值:var 变量名 类型 = 值
1 | package main |
这种写法很好理解:
- 指定变量名
- 指定类型
- 指定初始值
它的优点是可读性很强,因为信息非常完整。
3.3 让编译器帮你推断类型:var 变量名 = 值
1 | package main |
这里你没有手动写类型,但 Go 编译器会根据右边的值自动推断:
name是stringage是intprice是float64isActive是bool
这就叫 类型推断。
你可以把它理解成:
类型依然存在,只是你不用每次都亲手写出来。
这一点非常重要。Go 是强类型语言,不是没有类型,只是有时候由编译器替你判断。
3.4 最常用写法:短变量声明 :=
1 | package main |
这是一种非常常见的 Go 写法。
:= 的作用本质上是:
- 声明变量
- 同时完成赋值
- 让编译器推断类型
它几乎等价于:
1 | var name = "Tom" |
只是写起来更简洁。
4. 为什么 Go 既有 var,又有 :=
这往往是初学者第一个真正会困惑的地方。
你可能会想:既然 := 很方便,那为什么还需要 var?
这个问题问得非常好。
4.1 := 适合什么场景
:= 适合:
- 在函数内部声明局部变量
- 声明时就有初始值
- 类型很容易从右侧看出来
例如:
1 | name := "Tom" |
这种写法非常自然、简洁。
4.2 var 适合什么场景
var 适合:
- 你想明确写出变量类型
- 你暂时没有初始值
- 你在包级作用域声明变量
- 你想用更清晰、更正式的声明方式
例如:
1 | var total int |
又比如,包级变量不能用 :=:
1 | package main |
这个场景下只能用 var,不能用 :=。
4.3 一个非常重要的规则
:= 只能在函数内部使用。
这句话你一定要记住。
也就是说,下面这样是错误的:
1 | package main |
因为函数外部不能使用短变量声明。
5. 一次声明多个变量
在 Go 中,你可以一次声明多个变量。
5.1 同一行声明多个变量
1 | package main |
这种写法适合多个变量类型相同的情况。
5.2 使用分组方式声明
1 | package main |
这种写法在变量较多时更整齐。
5.3 使用 := 同时声明多个变量
1 | package main |
这种写法也很常见。
6. 变量重新赋值与声明,不要混淆
这是初学者特别容易混的地方。
6.1 重新赋值用 =
1 | package main |
这里:
- 第一次用
:=,是声明变量并赋值 - 第二次用
=,是对已有变量重新赋值
6.2 不要对已经存在的同名变量反复用 :=
例如:
1 | package main |
这通常会报错,因为同一作用域下你不能把同一个变量再次当成“新变量”声明。
你应该写成:
1 | package main |
这个区别非常关键:
:=是“声明并赋值”=是“给已存在变量赋值”
7. 零值:Go 非常重要的基础概念
这一节很重要,很多后续知识都和它有关。
7.1 什么是零值
在 Go 中,如果一个变量声明了但没有手动赋值,它会自动得到该类型的默认值,这个默认值叫 零值。
不同类型的零值不同。
例如:
int的零值是0float64的零值是0bool的零值是falsestring的零值是空字符串""
示例:
1 | package main |
7.2 为什么零值设计很重要
很多语言里,未初始化变量可能是危险的;但 Go 的思路是:
让变量即使没有显式赋值,也处于一个可预期状态。
这样做有几个好处:
- 降低未初始化风险
- 让代码行为更稳定
- 让很多结构体字段天然具备默认基础状态
你后面学结构体、切片、map、指针时,会越来越感受到零值的意义。
8. 常量:不会变化的值
变量是可以改变的,而常量通常是定义后不再变化的值。
在 Go 中,常量使用 const 声明。
8.1 基本写法
1 | package main |
这里:
pi是常量siteName也是常量
它们和变量最大的区别是:不能被重新赋值。
例如下面这样会报错:
1 | const pi = 3.14 |
8.2 为什么要用常量
常量适合表示那些程序运行期间不会变化的值,例如:
- 圆周率近似值
- 固定状态码
- 固定配置标识
- 业务中的常量文本
使用常量的好处是:
- 语义更明确
- 避免误修改
- 代码更容易维护
8.3 常量也可以分组声明
1 | const ( |
这种写法在定义一组固定值时很常见。
8.4 常量和变量的本质区别
你可以这样理解:
- 变量:运行过程中可能变化
- 常量:一旦定义,不允许变化
再从工程角度理解:
- 会变的数据,用变量
- 不该变的规则值,用常量
这是一种很重要的编码习惯。
9. 基础数据类型概览
Go 的基础数据类型并不算特别多,但每个都非常重要。
这一课先建立一个清晰地图。
9.1 布尔类型:bool
布尔值只有两个:
truefalse
示例:
1 | package main |
bool 常用于:
- 条件判断
- 状态标识
- 开关控制
零值是:
1 | false |
9.2 整数类型
Go 提供了多种整数类型,例如:
intint8int16int32int64uintuint8uint16uint32uint64
其中最常用的是:
intint64
新手阶段怎么选
一个非常实用的建议是:
没有特殊需求时,优先用
int。
因为:
- 它最自然
- 最常用
- 和很多标准库配合方便
如果你明确知道需要更大范围、或者需要和数据库字段、协议字段严格对齐,再考虑 int64 等更具体类型。
示例:
1 | package main |
关于无符号整数 uint
uint 表示无符号整数,也就是不能表示负数。
虽然它看起来适合表示“不会小于 0 的值”,但在实际业务开发中,很多时候并不建议新手随便使用 uint,因为:
- 它和
int混用容易带来类型问题 - 某些场景转换不够自然
实战中的经验是:
如果没有非常明确的理由,先优先用
int。
9.3 字节类型:byte
byte 本质上是 uint8 的别名。
它常用于表示:
- 一个字节的数据
- 二进制内容
- ASCII 字符
例如:
1 | package main |
这里你会看到输出的是对应的数值编码。
后面讲字符串、字节切片、文件和网络读写时,byte 会非常重要。
9.4 字符类型:rune
rune 本质上是 int32 的别名,常用于表示一个 Unicode 码点。
先不用急着深挖,只需要先建立一个印象:
byte更偏字节rune更偏字符语义
例如中文字符、emoji 等场景,后面讲字符串时会详细展开。
9.5 浮点类型:float32 和 float64
Go 中最常见的浮点数类型是:
float32float64
通常更常用的是:
float64
原因是精度更高,也更常见。
示例:
1 | package main |
这里如果你直接写 19.99,编译器通常会推断成 float64。
一个实战提醒
浮点数适合表示“近似小数”,但不适合直接处理需要绝对精确的金额计算。
例如:
- 科学计算、比例、平均值,用浮点数通常没问题
- 金额计算,需要更谨慎,后面工程实践里我会专门讲
你现在先建立这个意识即可。
9.6 字符串类型:string
字符串用来表示文本。
示例:
1 | package main |
字符串的零值是:
1 | "" |
也就是空字符串。
字符串的一个重要特征
你现在先记住一句话:
Go 中的字符串是只读的文本值。
后面我们会专门用一整课深入讲:
- 字符串长度
- 中文字符问题
byte与rune的区别- 字符串拼接
- 常用字符串处理函数
这一课先不展开太深。
10. 类型推断到底怎么理解
很多有其他语言经验的人,会把类型推断误解成“Go 类型不严格”。这是错误的。
10.1 Go 依然是强类型语言
例如:
1 | package main |
这里:
age不是“随便什么都能放”,它已经被确定为某种整数类型name也不是“任何类型都能塞进去”,它已经是string
所以类型推断只是:
编译器替你决定类型,而不是取消类型。
10.2 为什么 Go 要支持类型推断
它解决的是一个很现实的问题:
1 | var name string = "Tom" |
这里右边已经明显是字符串,再重复写一遍 string 有时会显得冗余。
所以 Go 提供:
1 | name := "Tom" |
这样更简洁。
这也是 Go 的典型风格:
- 保持强类型
- 避免无意义啰嗦
11. 类型不一致时,Go 不会“替你乱猜”
Go 在类型上比较严格,这其实是优点。
例如某些语言允许你随意混合不同数值类型,但 Go 通常要求你明确处理。
比如:
1 | package main |
虽然这段代码本身没问题,但如果你想直接把 a 和 b 相加,往往就会遇到类型不一致问题。
这体现了 Go 的原则:
类型要明确,转换要显式。
这种设计会让代码更安全,也更容易排查问题。
详细的类型转换,我们放到下一课重点展开。
12. 常见坑总结
这一节非常重要,我把新手在变量、常量和基础类型阶段最容易踩的坑给你提前列出来。
12.1 把 := 和 = 搞混
记忆口诀:
:=用于声明并赋值=用于给已有变量赋值
12.2 在函数外使用 :=
这是错误的。
函数外只能用 var 或 const。
12.3 定义了变量但没有使用
Go 编译器会报错。
例如:
1 | package main |
如果 name 没被使用,编译时通常就会出错。
这不是针对你,而是 Go 的统一规则:
- 保持代码干净
- 避免无意义变量残留
12.4 以为 var 没赋值就会是随机值
不会。Go 有零值机制。
这是它和某些语言不同的重要特征。
12.5 随便使用 uint
新手不要因为“某个值不可能为负”就本能地改用 uint。
工程里优先考虑一致性和可维护性,通常先用 int 更稳妥。
12.6 把字符串、数字、布尔当成可以随意混用
Go 是强类型语言,不会帮你做很多模糊处理。
后面涉及输入输出和类型转换时,你会更明显感受到这一点。
13. 一段综合示例
下面用一段代码,把本课核心知识串起来。
1 | package main |
你要能自己解释清楚:
- 哪些是变量
- 哪些是常量
- 哪些使用了零值机制
- 哪些使用了类型推断
- 哪些地方用了重新赋值
如果你能把这段代码完整拆解明白,这节课就掌握得很不错了。
14. 本课练习
一定要亲手写,不要只看。
练习 1:声明并输出你的个人信息
要求:
- 声明姓名
- 声明年龄
- 声明所在城市
- 声明是否已经开始学习 Go
- 把它们打印出来
建议同时使用:
var:=
目的是感受两种写法的差别。
练习 2:体验零值
要求:
- 用
var声明一个string - 用
var声明一个int - 用
var声明一个bool - 不赋值,直接打印
观察输出结果,并尝试自己解释为什么会这样。
练习 3:体验重新赋值
要求:
- 先声明一个年龄变量,值设为
18 - 然后把它改成
19 - 打印修改后的值
重点体会:
- 第一次为什么用
:=或var - 第二次为什么只能用
=
练习 4:定义常量
要求:
- 定义一个常量保存网站名称
- 定义一个常量保存班级名称
- 打印它们
然后你可以故意尝试修改常量,观察编译器报错。
练习 5:混合声明
自己写一个程序,里面同时包含:
constvar:=intfloat64boolstring
把它当成本课的小总结作业。
15. 自测题
你可以不看文档,试着回答下面的问题。
15.1 概念题
:=和=的区别是什么?- 为什么 Go 既需要
var,又需要:=? - 什么是零值?
string的零值是什么?bool的零值是什么?- 为什么说 Go 是强类型语言?
- 包级变量为什么不能用
:=? - 没有特殊需求时,为什么建议优先使用
int?
如果你能流畅回答这些问题,就说明你已经不只是“看懂”,而是开始形成自己的理解了。
16. 本课总结
这一课你学到的,不只是几个声明语法,而是 Go 变量系统背后的设计思路。
你现在应该已经理解:
- 变量是保存数据的命名空间
- Go 提供
var和:=两种常见声明方式 :=更简洁,但只能在函数内部使用=是重新赋值,不是声明- 零值让未显式赋值的变量也有可预期状态
- 常量用
const声明,适合不会变化的值 - 基础类型里最常用的是
bool、int、float64、string - Go 的类型推断并不等于弱类型,它本质上依然是强类型语言
如果把这一课打牢,你写 Go 时就不会总在“声明变量”这一步反复卡住。
17. 下一课预告
下一课我们进入:输入输出与类型转换。
会重点讲:
fmt.Print、fmt.Println、fmt.Printf的区别- 如何格式化输出变量
- 如何从控制台读取输入
- 为什么类型转换在 Go 里必须显式进行
int、float64、string之间如何转换- 新手最容易遇到的格式化输出错误
这一课会非常实用,因为从下一课开始,你写的程序会更像“真正能交互的小程序”。





