
在 go 中,当函数需同时返回结构体和错误时,应返回该结构体类型的零值(如 config{}),这是符合 go 惯例的安全做法;若返回指针类型,则可返回 nil,必要时也可返回部分有效数据与错误共存。
Go 的错误处理强调明确性与一致性:每个返回结构体的函数都应保证其返回值在任何路径下都是合法、可赋值的。因此,当发生错误时,返回对应类型的零值是标准且推荐的做法——它既避免了未定义行为,又符合 Go 的“显式优于隐式”哲学。
例如,你提供的 LoadConfig 函数完全符合 Go 惯例:
func LoadConfig(location string) (Config, error) {
configFile, err := ioutil.ReadFile(location)
if err != nil {
return Config{}, err // ✅ 返回零值结构体,清晰、安全、惯用
}
var config Config
if err := json.Unmarshal(configFile, &config); err != nil {
return Config{}, err // ✅ 同样返回零值,而非留空或 panic
}
return config, nil
}⚠️ 注意事项:
- 永远不要返回未初始化或部分构造的结构体(如只填充了部分字段)——这会破坏调用方对返回值确定性的假设;
- 若结构体较大或构造代价高,可考虑改用指针返回:func LoadConfig(...) (*Config, error),出错时直接返回 nil, err,既节省内存又语义更清晰;
- 极少数场景(如流式解析、增量读取)允许“部分成功”语义,此时可像 bufio.Reader.ReadString 那样返回已读数据 + 错误(如 io.EOF),但必须在文档中明确说明此行为,且仅适用于其设计意图本就支持中间状态的接口。
总结:零值返回是 Go 错误处理的基石。它简洁、可靠、无需额外约定,是绝大多数函数(包括标准库如 json.Unmarshal、os.Stat)所遵循的范式。坚持这一原则,你的 API 将更易理解、更难误用。










