- 定义和调用函数(值/指针参数)
- 掌握多返回值与命名返回
- 使用可变参数与闭包
- 理解函数是一等公民的意义
- 函数签名、传值语义、指针参数
- 多返回值与错误返回规范
- 可变参数与 ... 展开
- 匿名函数与闭包,函数作为参数
- 纯函数 vs 有副作用的选择
- Go 一律按值传递;想要修改调用方数据用指针参数:
func set(n *int) { *n = 1 } - 函数可以返回多个值,通常把数据与
error放在一起返回:func load(id int) (User, error) - 使用命名返回值时,建议只在简短函数或需要
defer修改返回值时使用,否则保持未命名更清晰。
示例:
// 传值:调用者不会被修改
func addCopy(n int, delta int) {
n += delta // 只改副本
}
// 传指针:调用者会被修改
func addPtr(n *int, delta int) {
*n += delta
}
// 命名返回值可配合 defer 微调结果
func loadName(id int) (name string, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("load %d: %w", id, err)
}
}()
switch id {
case 1:
return "alice", nil
case 2:
return "bob", nil
default:
return "", errors.New("not found")
}
}- 返回
(T, error)时,调用方先判错再用值:v, err := f(); if err != nil { return err } - 错误信息应描述失败原因,并携带关键数据:
fmt.Errorf("load %d: %w", id, err) - 避免用
panic作为普通错误处理;panic仅用于不可恢复的编程错误。
示例:
func openConfig(path string) (Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return Config{}, fmt.Errorf("read %q: %w", path, err)
}
var cfg Config
if err := json.Unmarshal(data, &cfg); err != nil {
return Config{}, fmt.Errorf("parse %q: %w", path, err)
}
return cfg, nil
}- 可变参数:
func sum(nums ...int) int;调用时sum(1, 2, 3)。 - 将切片展开传入:
sum(vals...),注意空切片也可展开。 - 可变参数底层就是切片,修改会影响同一底层数组;若不希望被修改,复制一份。
示例:
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
vals := []int{1, 2, 3}
fmt.Println(sum(vals...)) // 6- 函数是“一等公民”,可赋值给变量、作为参数或返回值。
- 匿名函数可立即调用:
func(msg string) { fmt.Println(msg) }("hi") - 闭包捕获外部变量的引用,循环中使用时要注意变量复用问题,例如在
for中传参避免共享同一迭代变量。
示例:
// 立即调用
func() { fmt.Println("once") }()
// 返回闭包
func newCounter(start int) func() int {
i := start
return func() int {
i++
return i
}
}
// Go 1.22+ 的 for range 每次迭代都是新变量,无需再复制 i
var fns []func()
for i := range []int{0, 1, 2} {
fns = append(fns, func() { fmt.Println(i) })
}
fns[0]() // 0- 纯函数:仅依赖输入,无外部状态,重复调用返回相同结果(便于测试与推理)。
- 有副作用的函数:读写 IO、全局变量、时间等。尽量将副作用集中、隔离,方便测试和替换。
示例:
// 纯函数
func add(a, b int) int { return a + b }
// 有副作用:读取时间
func stamp(msg string) string {
return fmt.Sprintf("%s @ %s", msg, time.Now().Format(time.RFC3339))
}- 可以为函数定义类型,方便复用签名:
type Pred func(int) bool - 高阶函数:参数或返回值是函数。
示例:
type Pred[T any] func(T) bool
func Filter[T any](xs []T, p Pred[T]) []T {
var out []T
for _, x := range xs {
if p(x) {
out = append(out, x)
}
}
return out
}
evens := Filter([]int{1, 2, 3, 4}, func(n int) bool { return n%2 == 0 })
fmt.Println(evens) // [2 4]写一个函数 Average(nums ...float64) (float64, error),当输入为空时返回错误。