今日目标
1️⃣ 建立 正确的 Go 语言心智模型
2️⃣ 搭好标准开发环境
3️⃣ 明白:为什么 Go 代码要“这样写”
一、为什么 Go 语言“看起来简单,却不容易写好”
如果你有 Java / PHP / Python / C++ 经验,第一感觉通常是:
- 语法很少
- 没有继承、异常、泛型(旧版本)
- 很多“高级特性”缺失
但 Go 的核心价值不在语法,而在 工程约束。
二、Go 的三大设计哲学(必须记住)
1️⃣ 显式优于隐式(Explicit is better than implicit)
体现在哪里?
- 错误是返回值,不是异常
- 没有隐式类型转换
- 没有默认参数
- 接口是显式方法集合
示例:错误处理是显式的
v, err := strconv.Atoi("123")
if err != nil {
// 必须显式处理
fmt.Println(err)
}
过程说明
err是普通返回值- 不处理就会被你“看到”
结论
Go 不替你“兜底”,但保证你“看得到风险”
2️⃣ 组合优于继承(Composition over inheritance)
Go 没有继承,但有两种组合方式:
- struct 嵌入
- interface 组合
示例:struct 嵌入
type Logger struct{}
func (l *Logger) Log(msg string) {
fmt.Println("log:", msg)
}
type Service struct {
Logger
}
func main() {
s := Service{}
s.Log("hello")
}
过程说明
Service没有继承Logger- 只是“拥有”一个 Logger 的能力
结论
Go 组合的是“能力”,不是“血缘关系”
3️⃣ 简单优于聪明(Simplicity over cleverness)
Go 追求:
- 易读
- 易维护
- 易协作
不追求:
- 炫技
- 极致抽象
- DSL 风格代码
示例:for 是唯一循环
for i := 0; i < 3; i++ {
fmt.Println(i)
}
没有:
- while
- do-while
- foreach(语法级)
结论
Go 把复杂度留给架构,不留给语法
三、Go 的执行模型(先有整体感)
Go 程序从 main 包的 main 函数开始执行。
package main
func main() {
// 程序入口
}
必须遵守的规则
- 每个可执行程序 只能有一个 main 包
- main 包中 必须有 main()
四、Go 开发环境搭建(标准做法)
1️⃣ 安装 Go(略)
验证:
go version
2️⃣ Go Module(非常重要)
Go 现在 强制使用 module,不再依赖 GOPATH。
初始化一个项目
mkdir hello-go
cd hello-go
go mod init hello-go
生成:
go.mod
3️⃣ 第一个 Go 程序
// main.go
package main
import "fmt"
func main() {
fmt.Println("Hello, Go")
}
运行:
go run main.go
结果
Hello, Go
五、Go 的基础工具链(每天都会用)
1️⃣ go run
- 编译 + 运行
- 适合开发期
go run main.go
2️⃣ go build
- 只编译,生成二进制
go build
结果:
./hello-go
3️⃣ go fmt(强制风格)
go fmt ./...
重要认知
Go 代码风格不是“建议”,而是“强制”
4️⃣ go vet(静态检查)
go vet ./...
六、package 与 import 的基本规则
1️⃣ package 是编译单元
package main
- 同目录下文件必须同 package
- package 名不一定等于目录名(但强烈建议一致)
2️⃣ import 规则
import (
"fmt"
"time"
)
- 未使用的 import 会 直接编译失败
- 这是 Go 的刻意设计
七、你今天必须理解的 5 个关键点
- Go 是 工程语言,不是学术语言
- 显式错误是优点,不是缺点
- 没有继承 ≠ 表达能力弱
- 工具链是语言的一部分
- 写 Go 是在为“未来的维护者”负责
八、Day 1 实践任务(必须做)
任务 1:初始化项目
mkdir go-study
cd go-study
go mod init go-study
任务 2:写一个最小程序
要求:
- 使用 fmt
- 至少一个函数
package main
import "fmt"
func hello(name string) {
fmt.Println("hello", name)
}
func main() {
hello("Go")
}
运行结果
hello Go
任务 3:故意犯错并修复
1️⃣ 删除 fmt 的使用
2️⃣ 运行 go build
3️⃣ 阅读错误信息并修复
九、自检清单(非常重要)
在进入 Day 2 前,你应该能回答:
- Go 为什么不用异常?
- package 的边界是什么?
- go fmt 为什么是强制的?
- Go 的“简单”体现在哪里?
如果有任何一个答不上来,不要急着往后学。
预告:Day 2 学什么
Day 2|变量、控制流与值语义
你将彻底搞清楚:
- Go 为什么“到处拷贝”
- 为什么新手 Go 代码容易写 Bug
- defer 的真正执行顺序
- for + goroutine 的经典坑