Go 入门 03
函数 · 包 · 错误处理
把代码组织成能被别人调用的形状
func函数
2返回值
error错误值
Chapter 03
函数是 Go 代码组织的基本动作
函数把一段行为命名,并通过参数和返回值暴露给调用者。Go 的函数签名很直接:参数写在括号里,返回值写在参数列表后面。多个连续参数类型相同时,可以把类型写在最后。
func add(left, right int) int {
return left + right
}
func divide(total, count int) (int, bool) {
if count == 0 {
return 0, false
}
return total / count, true
}
Go 支持多返回值,这让“结果 + 状态”或“结果 + 错误”成为自然写法,而不必借助异常控制普通失败路径。
Packages
包边界与导出名
包用于组织相关函数、类型、变量和常量。官方教程强调,Go 代码按包分组,包再归入模块。一个名字是否能被其他包访问,由首字母大小写决定:大写开头是导出名,小写开头只在当前包内可见。
package greetings
import "fmt"
func Hello(name string) string {
return fmt.Sprintf("Hi, %s. Welcome!", name)
}
func internalMessage() string {
return "only visible inside greetings"
}
Hello 可以被其他包调用,internalMessage 不会成为包的公共 API。这个规则简单,但很关键:你可以用命名直接表达模块边界。
命名原则:不要为了“以后也许会用”而导出名字。先保持内部实现小写,等外部确实需要稳定 API 时再导出。
Errors
错误是值,不是隐藏控制流
Go 的错误处理核心是内置 error 接口。官方博客说明,Go 代码通常用非 nil 的 error 值表示异常状态;调用者显式检查错误,再决定如何处理。
定义:error
error 是一个接口,包含 Error() string 方法。任何实现这个方法的类型都可以作为错误值。
package greetings
import (
"errors"
"fmt"
)
func Hello(name string) (string, error) {
if name == "" {
return "", errors.New("empty name")
}
return fmt.Sprintf("Hi, %s. Welcome!", name), nil
}
调用者需要检查错误:
message, err := greetings.Hello("")
if err != nil {
log.Fatal(err)
}
fmt.Println(message)
这种写法看起来比异常冗长,但好处是失败路径在代码里可见。你能直接看到哪个调用可能失败、失败后是否返回、重试、记录日志或转换为上层错误。
API Design
写给调用者看的函数
好的 Go 函数通常具备三个特征:名字说明动作,参数数量克制,错误上下文清楚。返回错误时,不要只写“failed”,要让调用者知道失败发生在哪个动作上。
func LoadConfig(path string) ([]byte, error) {
content, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("load config %q: %w", path, err)
}
return content, nil
}
%w 会包装底层错误,让上层既能看到上下文,也能继续用 errors.Is 或 errors.As 判断错误类型。
不要吞掉错误
如果函数返回了 err,调用者就应该明确处理它。忽略错误会让真实故障延迟到更远处爆发,调试成本更高。
复习速查
- 函数:用参数输入,用返回值输出。
- 多返回值:Go 常用
(result, error)表达可能失败的调用。 - 导出名:大写开头能被其他包访问,小写开头仅包内可见。
- 错误上下文:用
fmt.Errorf("...: %w", err)包装底层错误。
参考来源
- The Go Authors. Tutorial: Create a Go module. go.dev/doc/tutorial/create-module
- Gerrand, A. Error handling and Go. go.dev/blog/error-handling-and-go
- The Go Authors. How to Write Go Code. go.dev/doc/code