4. 函数与包
这是什么:函数 = 起好名字的一段代码,可以收参数、交结果;包(package) = 把函数按目录打包,跨文件互相调用。
为什么用:上一章数据存进了变量,可代码全堆在 main 里,重复逻辑抄三遍、改一处就得改三处。用函数打包逻辑、用包分组文件,代码才长得下去。
如何用:先写一个最普通的 add 函数,再体验 Go 招牌的多返回值 (result, error),最后把函数分到不同包里用 import 串起来。
4.1 基本函数
func add(a int, b int) int {
return a + b
}
// 同类型连续参数可简写 a, b int
4.2 多返回值(Go 的招牌)
错误处理线性可读的基石——结果 + 错误一起返回:
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为 0")
}
return a / b, nil // nil = 「没有错误」
}
func main() {
r, err := divide(10, 2)
if err != nil {
fmt.Println("出错:", err)
return
}
fmt.Println(r)
}
5
官方模式:调用函数先接 err、先判断 err——本章贯通第 6 章 error 处理。
4.3 命名返回值与 defer
func calc() (sum int) {
defer fmt.Println("函数结束啦") // defer:函数 return 前才执行
sum = 42
return // 命名返回:自动返回 sum
}
defer 常用来「收尾」(关文件、解锁),后进先出。
4.4 可变参数与匿名函数
func sumAll(nums ...int) int { // ...int 可变参数
total := 0
for _, n := range nums { // _ 丢弃 index
total += n
}
return total
}
sumAll(1, 2, 3) // 6
go func() { fmt.Println("并发!") }() // 匿名函数直接起 goroutine
_是弃位符:不想要的值统统用_接,避免「未使用变量」报错。
4.5 包(package)与目录
hello/
├── go.mod
├── main.go (package main,入口)
└── utils/
└── math.go (package utils)
// utils/math.go
package utils
func Double(x int) int { return x * 2 } // 大写开头 = 可被外部访问(导出)
func hidden() {} // 小写开头 = 私有
// main.go
import "hello/utils"
fmt.Println(utils.Double(21)) // 42
要点:
- import 使用模块路径(go.mod 里的模块名 + 目录)
- 大写 = 公开,小写 = 私有(Go 用这招代替 public/private)
go build ./... # 编译整个项目
4.6 动手改
- 写
max(nums ...int)返回最大值,塞进 utils 并在 main 调用 - 用 defer 顺序体会「后进先出」
- 故意调私有
utils.hidden()看编译报错
4.7 小结
- 多返回
(result, error),调用方先看 err - defer 收尾栈;
_弃位 - 大写导出、小写私有,import 按模块路径
下一章:结构体与方法 🐸