Skip to content

第02章 变量、常量与基本数据类型

本章目标:掌握 Go 的"原材料"——变量、常量和六大基本数据类型,以及类型转换的规则与坑。


1. 一切的起点:变量

🌰 生活化比喻

变量 = 储物柜

  • 储物柜有编号(变量名)
  • 储物柜有尺寸(数据类型 → 决定能放多大的东西)
  • 储物柜里装着东西(变量的值)
  • 你可以换柜子里的东西(赋值)
柜子编号 age (类型 int):[ 18 ] → 换成 [ 19 ]
柜子编号 name (类型 string):[ "Tom" ]

📊 配套图解:diagrams/variable-concept.svg

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
布尔 boolfalse
字符串 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 整型

类型大小范围
int81 字节-128 ~ 127
int162 字节-32768 ~ 32767
int324 字节约 ±21 亿
int648 字节约 ±900 亿亿
int4 或 8 字节跟随平台(64 位机器是 8 字节)
uint8 / byte1 字节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
byterune
别名uint8int32
大小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.Itoafmt.Sprintf("%d", n)

📊 配套图解:diagrams/type-conversion.svg


5. 内置函数 lencapnewmake

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章会深入讲 makenew 的区别。


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


📂 配套资源