01 起步与工具链
Go 1.27 工具链速查:go 命令全表、模块与工作区、环境变量、go run/build/install 差异、交叉编译与构建标记
10 分钟阅读
这不是教程,是字典。教程教你走路,字典只在你卡住时递上一根拐杖。所以本页写得密、写得短、写得没什么耐心——每一条都假设你已经会编程,只是记不清 Go 里这个动作该怎么写。
风格上参考 Rust Language Cheat Sheet,但内容完全按 Go 重写:Go 没有泛型继承、没有异常、没有析构函数,却有一等公民的 goroutine、隐式接口、值语义切片,还有一整套只有 go 命令才有的工程化约定。照搬没有意义,该不一样的地方就让它不一样。
语言版本基线:Go 1.27.1(写作时本机工具链实际版本)。凡是较新版本才引入的特性,都会当场标注 🆕 并写明起始版本;示例一律在该版本下实跑验证。
| 符号 | 含义 |
|---|---|
| 🔥 | 高频使用,值得先记住 |
| ⚠️ | 陷阱或易错点,踩过一次就该记住 |
| 🛑 | 错误示例,故意写错给你看 |
| 🆕 | 较新版本才有的特性,注意 go.mod 里的 go 指令 |
| 🚧 | 有限制、仍在演进,或只在特定平台可用 |
| 🪦 | 已废弃(deprecated),新代码不要再用 |
| 🝖 | 偏深的内容,第一遍可以跳过 |
| 💭 | 笔者见解,不是官方定论 |
| ↪ | 等价写法或语法糖展开 |
| 📘 | 指向官方文档或权威资料 |
关于
// 输出::标的是这段代码真实跑出来的结果,全部在 Go 1.27.1 / darwin/arm64 下实跑核对。行尾的中文注解只是给人看的,不属于输出内容。
19 页不是随便切的,它按「写代码时的思维路径」分层:从怎么跑起来,到语言主干,再到并发与工程化。
flowchart TB
ROOT(["Go 速查表"])
subgraph L1["① 起步层:让代码跑起来"]
A1["01 起步与工具链<br/>go 命令 / 模块 / 交叉编译"]
A2["02 词法与语法骨架<br/>关键字 / 运算符 / 命名"]
end
subgraph L2["② 语言主干:类型、控制、函数"]
B1["03 类型与零值"]
B2["04 变量·常量·iota"]
B3["05 语句与控制流"]
B4["06 函数·方法·defer"]
end
subgraph L3["③ 数据与抽象"]
C1["07 数组·切片·映射·结构体"]
C2["08 接口与嵌入"]
C3["09 错误处理"]
C4["10 泛型"]
end
subgraph L4["④ 运行时与并发"]
D1["11 内存·指针·unsafe"]
D2["12 goroutine 与 channel"]
D3["13 sync·atomic·context"]
D4["18 并发模式"]
end
subgraph L5["⑤ 标准库与工程化"]
E1["14 strings 与数字"]
E2["15 io·fs·time"]
E3["16 编码·日志·slog"]
E4["17 测试"]
E5["19 陷阱与惯用法"]
end
ROOT --> L1 --> L2 --> L3 --> L4 --> L5如果你只有半小时,按这条线看;如果只是查一个语法,直接翻目录。
flowchart LR
S(["开始"]) --> Q1{"你会写 Go 吗?"}
Q1 -- "不会,从别的语言来" --> P1["02 → 03 → 05 → 06<br/>先能读懂语法"]
Q1 -- "会一点,总写错" --> P2["19 陷阱 → 07 切片/映射<br/>先止血"]
Q1 -- "会写,要并发" --> P3["12 → 13 → 18<br/>goroutine 到模式"]
Q1 -- "会写,要上线" --> P4["17 测试 → 01 工具链<br/>→ 16 日志"]
P1 --> DONE(["能干活"])
P2 --> DONE
P3 --> DONE
P4 --> DONE| 主题 | 内容一句话 |
|---|---|
| 01 起步与工具链 | go 命令全表、模块初始化、go run/build/install 差异、交叉编译 |
| 02 词法与语法骨架 | 25 个关键字分组、运算符优先级、分号插入规则、命名与导出 |
| 03 类型与零值 | 类型体系全景、数值边界表、rune/byte/string、零值总表 |
| 04 变量·常量·iota | var/:=/批量声明、无类型常量、iota 六种惯用模式 |
| 05 语句与控制流 | if 带初始化、for 三形态、range 语义、switch/goto |
| 06 函数·方法·defer | 多返回值、变参、闭包、方法集、defer 时序、panic/recover |
| 07 数组·切片·映射·结构体 | 切片三字段头、扩容、三索引切片、map 底层、struct tag 与对齐 |
| 08 接口与嵌入 | 隐式实现、接口值二元组、nil 接口陷阱、类型断言、嵌入提升 |
| 09 错误处理 | 哨兵错误、%w 包装链、errors.Is/As/Join、自定义错误 |
| 10 泛型 | 类型参数、约束与 ~T、类型推断、泛型标准库 slices/maps |
| 11 内存·指针·unsafe | 逃逸分析、new vs make、GC、sync.Pool、unsafe 边界 |
| 12 goroutine 与 channel | GMP 调度、channel 语义、select 多路复用、生成器与管线 |
| 13 sync·atomic·context | 锁家族选型、atomic 操作表、context 取消树、errgroup |
| 14 标准库:字符串与数字 | strings/bytes/strconv/unicode/regexp/sort/slices/math |
| 15 标准库:io·fs·time | io.Reader 组合链、bufio、os/filepath、embed、time |
| 16 标准库:编码·日志 | encoding/json 全表、struct tag、log/slog 结构化日志 |
| 17 测试 | go test 生命周期、表驱动、子测试、基准、fuzz、mock 策略 |
| 18 并发模式 | worker pool、pipeline、fan-in/out、取消传播、优雅关闭 |
| 19 陷阱与惯用法 | 按症状索引的踩坑表 + 惯用法对照,Go 程序员的病历本 |
先让第一行代码跑起来。Go 的设计目标之一就是「装上就能编译」,从 1.16 起模块模式已是默认,不再需要 GOPATH。
不建模块也能跑单个文件,适合验证一小段语法:
| |
| |
fmt.Println 会在参数之间自动加空格、末尾补换行;要精细控制就用 fmt.Printf。
真正的项目从 go mod init 开始,它生成 go.mod 记录模块路径与依赖:
| |
main.go 与上面相同,然后 go build 得到可执行文件:
| |
Go 把测试做进了工具链,不需要第三方框架。文件名必须以 _test.go 结尾:
| |
| |
详见 17 测试。
这 15 条是「一天要用十次」级别的。每条都能在对应章节里找到完整展开。
| # | 我想干的事 | 写法 | 注意 |
|---|---|---|---|
| 1 | 声明并赋值 | x := 42 | 只能在函数内用;类型由右值推断 🔥 |
| 2 | 声明带类型 | var x int = 42 / var x int | 包级变量只能用 var |
| 3 | 错误处理 | v, err := f(); if err != nil { return err } | Go 没有异常,err 永远显式 🔥 |
| 4 | 忽略某个返回值 | _ = f() / v, _ := f() | _ 是空标识符,不是变量 |
| 5 | 打印 | fmt.Println(a, b) / fmt.Printf("%d\n", n) | 调试用 %+v 看字段名 |
| 6 | 遍历切片 | for i, v := range xs {} | 只要值用 for _, v := range xs;Go 1.22 起 v 每次迭代新建 🆕 |
| 7 | 追加元素 | xs = append(xs, x) | 必须接返回值,切片头可能被换掉 ⚠️ |
| 8 | 建映射 | m := map[string]int{} | m["k"]++ 不用先判存在;零值即 0 |
| 9 | 判映射键存在 | v, ok := m[k] | 用 ok,不要用 v != 0 判存在 ⚠️ |
| 10 | 定义结构体 | type User struct { Name string } | 字段首字母大写才能被外部包访问 |
| 11 | 取地址 / 解引用 | p := &u / *p | 结构体方法常用指针接收者 |
| 12 | 起一个 goroutine | go f(ctx) | 记得有退出路径,否则泄漏 ⚠️ |
| 13 | 发/收 channel | ch <- v / v := <-ch | 无缓冲 channel 会阻塞到对面就绪 |
| 14 | 带取消的上下文 | ctx, cancel := context.WithTimeout(ctx, 3*time.Second); defer cancel() | cancel 必须调用,否则泄漏 ⚠️ |
| 15 | 加锁 | mu.Lock(); defer mu.Unlock() | 锁值不可复制;用 go vet 能查出部分误用 |
Go 不是「更好的 C++」,它是一套明确取舍:用表达力换编译速度与工程一致性。
go + chan + select 三个关键字就能表达多数并发结构,不需要库。GOOS/GOARCH)。
⚠️ 「默认静态链接」要分平台说:Linux 上纯 Go 程序是静态链接的;想让交叉编译产物彻底不依赖系统库需 CGO_ENABLED=0;而在 macOS 上即使 CGO_ENABLED=0,二进制仍会链接 libSystem(见 01)。gofmt 终结格式争论,go vet/go test/go doc 全部内置,标准库质量高且向后兼容承诺明确。| 维度 | Go | Rust | Java | Python |
|---|---|---|---|---|
| 内存管理 | GC(并发三色标记) | 所有权 + 借用检查 | GC(分代) | 引用计数 + GC |
| 错误处理 | 返回值 error | Result<T, E> + ? | 异常 | 异常 |
| 并发模型 | goroutine(M:N 调度)+ channel | 线程 + async + Send/Sync | 线程 / 虚拟线程 | GIL / asyncio |
| 泛型 | 1.18 起,受限 | 完整 | 擦除式 | 鸭子类型 |
| 编译速度 | 极快 | 慢 | 中(JIT 预热) | 无编译期 |
| 部署产物 | 单个可执行文件(Linux 纯 Go 为静态) | 单个二进制 | 需要 JVM | 需要解释器 |
| 学习曲线 | 平缓(关键字仅 25 个) | 陡峭 | 中等 | 平缓 |
💭 Go 的定位是「工程语言」:让 50 人写出的代码看起来像 1 个人写的,比让 1 个人写出最优雅的代码更重要。
| |
| |
| |
国内环境先把模块代理换成可用的镜像,否则 go get 会超时:
| |
⚠️ direct 必须保留在列表末尾,表示「代理不可用时直连」。可用 go env -w 写入的值,go env -u 撤销。
装完做一次「四连验证」,四项全过说明工具链完好:
| |
理解这条流水线,你才能在「报错不知道在哪一步」时定位问题。
flowchart LR
SRC["hello.go<br/>源码"] -->|"go build"| COMPILE
MOD["go.mod / go.sum<br/>依赖清单"] --> COMPILE
subgraph COMPILE["编译链路(go 命令自动调度)"]
direction TB
P["compile<br/>→ .a 归档"] --> L["link<br/>→ 可执行文件"]
end
COMPILE --> CACHE[("构建缓存<br/>GOCACHE")]
CACHE -.->|"命中则跳过"| COMPILE
COMPILE --> BIN["demo<br/>静态二进制"]
BIN -->|"go run"| RUN["直接执行"]
BIN -->|"go install"| GOBIN["$GOBIN<br/>或 $GOPATH/bin"]关键点只有两条:
GOCACHE 命中时编译几乎是瞬间的,go build -a 可以强制全量重建(排查「本地能过 CI 不能过」时偶尔有用)。go run 不落盘:它把二进制放进临时目录再执行,所以生产环境不要依赖它的产物路径。| 术语 | 含义 |
|---|---|
| module | 一个 go.mod 定义的版本化单元,是依赖管理的最小单位 |
| package | 同一目录下同 package xxx 的一组 .go 文件,是编译的最小单位 |
| goroutine | 由 Go 运行时调度的轻量执行单元,初始栈 2 KB,可增长 |
| channel | 带类型的管道,goroutine 间通信与同步的载体 |
| interface | 一组方法签名的集合,隐式实现,Go 唯一的抽象机制 |
| zero value | 未显式初始化的变量的默认值:0/""/nil/false |
| escape analysis | 编译期判断变量该放栈还是堆的分析(见 11 内存) |
| GMP | Goroutine / Machine / Processor 三层调度模型(见 12 并发) |
| cgo | 调用 C 代码的机制,会破坏静态链接并拖慢编译 🚧 |
准备好了?从 01 起步与工具链 开始,或直接跳到你在找的那一页。
Go 1.27 工具链速查:go 命令全表、模块与工作区、环境变量、go run/build/install 差异、交叉编译与构建标记
Go 的词法要素速查:25 个关键字分组、预声明标识符、字面量写法、运算符优先级、分号插入规则、命名与导出
Go 类型体系全景:基本类型与取值范围、rune/byte/string 的关系、UTF-8 语义、零值总表、类型转换规则
Go 变量与常量速查:var / := / 批量声明、包级与局部差异、无类型常量、iota 六种惯用模式与陷阱
Go 语句速查:if 带初始化语句、for 三种形态、range 在各类型上的语义、Go 1.22 循环变量变更、switch 与 fallthrough、标签跳转
Go 函数与方法速查:多返回值、命名返回、变参、闭包、方法集与接收者选择、defer 求值时机与执行顺序、panic/recover
Go 复合类型速查:数组与切片的内存结构、len/cap/扩容、三索引切片、append 别名陷阱、map 底层与操作、struct 标签与内存对齐
Go 接口速查:隐式实现、接口值二元组结构、nil 接口与 nil 指针的区别、类型断言、类型 switch、结构体与接口嵌入、方法提升
Go 错误处理速查:error 接口、哨兵错误、%w 包装链、errors.Is/As/Join/Unwrap、自定义错误类型、panic 与 error 的边界
Go 泛型速查:类型参数语法、约束与 ~T、类型推断、泛型类型与方法、标准库 slices/maps/cmp、真正的限制清单
Go 内存速查:栈与堆、逃逸分析判据、new 与 make 的区别、GC 与调优旋钮、sync.Pool、unsafe 包的安全边界
Go 并发速查:GMP 调度模型、goroutine 生命周期、channel 三种状态、close 语义、select 多路复用、超时与取消、生成器与管线
Go 同步速查:Mutex/RWMutex/WaitGroup/Once/Cond/Pool 选型、atomic 全部类型与操作、context 取消树与派生函数、errgroup 与 semaphore
Go 标准库速查:strings/bytes 全函数表、Builder 与迭代器、strconv 转换决策、unicode、regexp、sort、slices、maps、cmp、math
Go 标准库速查:io.Reader/Writer 装饰器组合、bufio 与 Scanner 陷阱、os 与 filepath、fs.FS 与 embed、os/exec、time 格式化与定时器
Go 标准库速查:encoding/json 全表与 tag 语义、自定义 Marshaler、json.RawMessage、base64 与压缩、log 与 log/slog 结构化日志
Go 测试速查:go test 全参数、表驱动与子测试、并行与 helper、示例函数、基准测试 B.Loop、模糊测试、httptest/fstest/synctest、测试替身策略
Go 并发模式速查:worker pool、pipeline、fan-in/fan-out、取消与超时、优雅关闭、限流背压、goroutine 泄漏排查
Go 陷阱总表:按症状索引的高频 bug、以为 vs 实际对照、从 C/Java/Python 迁来的思维定势、Go 惯用法与反模式