ESC
输入关键词搜索文章
目录

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.Iserrors.As 判断错误类型。

不要吞掉错误

如果函数返回了 err,调用者就应该明确处理它。忽略错误会让真实故障延迟到更远处爆发,调试成本更高。

复习速查

  • 函数:用参数输入,用返回值输出。
  • 多返回值:Go 常用 (result, error) 表达可能失败的调用。
  • 导出名:大写开头能被其他包访问,小写开头仅包内可见。
  • 错误上下文:用 fmt.Errorf("...: %w", err) 包装底层错误。

参考来源