主题
第02章 变量、常量与基本数据类型
本章目标:掌握 Go 的"原材料"——变量、常量和六大基本数据类型,以及类型转换的规则与坑。
1. 一切的起点:变量
🌰 生活化比喻
变量 = 储物柜:
- 储物柜有编号(变量名)
- 储物柜有尺寸(数据类型 → 决定能放多大的东西)
- 储物柜里装着东西(变量的值)
- 你可以换柜子里的东西(赋值)
柜子编号 age (类型 int):[ 18 ] → 换成 [ 19 ]
柜子编号 name (类型 string):[ "Tom" ]1.1 四种声明方式
go
// 方式1:标准声明 var 名字 类型 = 值
var age int = 18
// 方式2:类型推导(Go 自动推断类型)
var name = "Tom" // string
// 方式3:短变量声明(最常用,仅函数内可用)
score := 95.5 // float64
// 方式4:批量声明
var (
a int = 1
b string = "hello"
c bool = true
)💡 黄金法则:函数内用
:=,包级别变量用var。
1.2 零值(Zero Value)
Go 里所有变量都有默认值,称为零值——你不用担心忘记初始化导致随机数据。
| 类型 | 零值 |
|---|---|
| 整型 (int, int32...) | 0 |
| 浮点 (float32, float64) | 0.0 |
| 布尔 bool | false |
| 字符串 string | ""(空串,不是 nil) |
| 指针、切片、map、channel、接口、函数 | nil |
go
var x int // x = 0
var s string // s = "",不是 nil!
var p *int // p = nil📊 配套图解:diagrams/zero-values.svg
2. 常量:用 const 锁住值
go
const Pi = 3.14159
const (
StatusOK = 200
StatusError = 500
)常量 vs 变量:
| 变量 var | 常量 const | |
|---|---|---|
| 编译期可计算 | ❌ | ✅ |
| 可被修改 | ✅ | ❌ |
| 可寻址(取地址) | ✅ | ❌ |
2.1 iota:自动递增神器
go
const (
Sunday = iota // 0
Monday // 1
Tuesday // 2
Wednesday // 3
// 后面 iota 在每行自动 +1
)🌰 生活化比喻:iota 像自动取号机,每经过一行自动 +1。
go
const (
KB = 1 << (10 * (iota + 1)) // 2^10 = 1024
MB // 2^20
GB // 2^30
TB // 2^40
)📊 配套图解:diagrams/iota-magic.svg
3. 六大基本数据类型
3.1 整型
| 类型 | 大小 | 范围 |
|---|---|---|
int8 | 1 字节 | -128 ~ 127 |
int16 | 2 字节 | -32768 ~ 32767 |
int32 | 4 字节 | 约 ±21 亿 |
int64 | 8 字节 | 约 ±900 亿亿 |
int | 4 或 8 字节 | 跟随平台(64 位机器是 8 字节) |
uint8 / byte | 1 字节 | 0 ~ 255 |
uint16/32/64 | 同上无符号 | 0 ~ 2^N-1 |
💡 新手只需记住:默认用
int,不需要纠结具体位数。需要存一个字节用byte,需要表示 Unicode 字符用rune。
3.2 浮点型
go
var price float64 = 19.99 // 64 位双精度(推荐)
var ratio float32 = 0.618 // 32 位单精度(精度不够,少用)⚠️ 浮点精度坑:
go
fmt.Println(0.1 + 0.2) // 输出 0.30000000000000004(IEEE 754 标准)金额计算别用 float!用整数(以分为单位)或专用 decimal 库。
3.3 布尔型
go
var ok bool = true
var done = false⚠️ Go 中0 不是 false,1 不是 true!必须显式用 true/false。
go
var x int = 0
if x { ... } // ❌ 编译错误!
if x != 0 { ... } // ✅3.4 字符串
字符串是只读的字节序列(UTF-8 编码)。
go
s := "Hello, 世界"
fmt.Println(len(s)) // 13(按字节算!)
fmt.Println(len([]rune(s))) // 9 (按字符算)🌰 生活化比喻:字符串就像水泥砌好的墙——一旦建成不能改单块砖,但你可以整面墙拆了重砌:
go
s := "hello"
// s[0] = 'H' // ❌ 编译错误:字符串不可变
s = strings.ToUpper(s) // ✅ 整体替换3.5 字符 byte 和 rune
go
var b byte = 'A' // ASCII 字符,本质是 uint8
var r rune = '中' // Unicode 字符,本质是 int32| byte | rune | |
|---|---|---|
| 别名 | uint8 | int32 |
| 大小 | 1 字节 | 4 字节 |
| 范围 | 0-255 (ASCII) | Unicode 全集 |
📊 配套图解:diagrams/types-overview.svg
4. 类型转换:必须显式
Go 不允许隐式类型转换,必须显式转。
go
var i int = 10
var f float64 = float64(i) // 必须显式
var u uint = uint(f)🌰 生活化比喻:Go 不像 Python 那样"啥都行",更像海关——入境必须报关。
4.1 常见转换
go
// int <-> string(注意!别想当然)
n := 65
s := string(n) // "A" (把 65 当 Unicode 码点解释)
s := strconv.Itoa(n) // "65" 才是你想要的
// string -> int
n, err := strconv.Atoi("42")
// int -> float
var f = float64(n)⚠️ 新手最常见错误:string(数字) 不会得到那个数字的字符串!必须用 strconv.Itoa 或 fmt.Sprintf("%d", n)。
📊 配套图解:diagrams/type-conversion.svg
5. 内置函数 len、cap、new、make
go
len("hello") // 5
len([]int{1, 2, 3}) // 3
len(map[string]int{...}) // 元素数
p := new(int) // 分配内存,返回指针,*p = 0
m := make(map[string]int) // 创建 map(make 用于 map/slice/channel)第05章会深入讲
make和new的区别。
6. 完整示例:温度转换器
go
package main
import "fmt"
const FreezingF = 32.0
func main() {
var celsius float64 = 25.0
fahrenheit := celsius*9/5 + FreezingF
fmt.Printf("%.1f°C = %.1f°F\n", celsius, fahrenheit)
}输出:25.0°C = 77.0°F
7. 本章小结
✅ 4 种变量声明方式:var、类型推导、:=、批量声明
✅ 所有变量都有零值,不用担心垃圾内存
✅ 常量用 const,配合 iota 写枚举非常爽
✅ 整型默认用 int,浮点用 float64
✅ 字符串不可变,按字节存储 UTF-8
✅ 类型转换必须显式,没有隐式转换
✅ string(65) 是 "A" 不是 "65",要用 strconv.Itoa
📂 配套资源
- examples/01_variables.go —— 各种变量声明
- examples/02_constants.go —— 常量与 iota
- examples/03_types.go —— 基本类型与转换
- examples/04_strings.go —— 字符串与 rune
- demo.html —— 浏览器可视化演示
- interview.md —— 面试题精选