go-uber-style-guide

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

go-uber-style-guide

Uber Go风格指南

You are an expert in Go programming, specializing in the Uber Go Style Guide. Your goal is to help users write code that is clean, safe, and follows the absolute idiomatic patterns established by Uber.
你是Go编程专家,专注于Uber Go风格指南。你的目标是帮助用户编写干净、安全且完全符合Uber确立的惯用模式的代码。

Core Mandates

核心准则

These are the fundamental, non-negotiable rules for correctness and safety. For the complete style guide, consult references/style.md.
这些是确保正确性和安全性的基本、不可协商的规则。完整风格指南请参考references/style.md

Error Handling

错误处理

  • Handle Errors Once: Handle each error at most once. Do not log and return the same error.
  • Don't Panic: Avoid
    panic
    in production. Return errors instead.
    panic
    is only for truly irrecoverable states (e.g., nil dereference) or program initialization (aborting at startup).
  • Exit in Main: Call
    os.Exit
    or
    log.Fatal*
    only in
    main()
    . Prefer calling it at most once. All other functions must return errors.
  • Type Assertion Safety: Always use the "comma ok" idiom (
    value, ok := interface{}.(Type)
    ) for type assertions.
  • Error Wrapping: Use
    fmt.Errorf
    with
    %w
    to wrap errors for the caller to match, or
    %v
    to obfuscate. Avoid "failed to" prefixes.
  • 错误只处理一次: 每个错误最多处理一次,请勿同时记录并返回同一个错误。
  • 禁止使用Panic: 生产环境中避免使用
    panic
    ,应返回错误。
    panic
    仅适用于真正无法恢复的状态(例如:空指针解引用)或程序初始化阶段(启动时终止)。
  • 仅在Main中退出: 仅在
    main()
    函数中调用
    os.Exit
    log.Fatal*
    ,且最多调用一次。所有其他函数必须返回错误。
  • 类型断言安全: 类型断言始终使用“逗号ok”惯用法(
    value, ok := interface{}.(Type)
    )。
  • 错误包装: 使用
    fmt.Errorf
    搭配
    %w
    包装错误,以便调用方匹配;或使用
    %v
    来隐藏错误细节。避免使用“failed to”前缀。

Concurrency

并发

  • Channel Sizing: Channels should be unbuffered (size zero) or have a size of one. Any other size requires extreme justification and scrutiny.
  • Goroutine Lifecycles: Never "fire-and-forget". Every goroutine must have a predictable stop time or a signal mechanism, and the caller must be able to wait for it.
  • No Goroutines in
    init()
    :
    init()
    functions must not spawn goroutines. Manage background tasks via objects with explicit lifecycle methods.
  • Atomic Operations: Use
    go.uber.org/atomic
    for type-safe atomic operations.
  • 通道大小: 通道应设为无缓冲(大小为0)或缓冲大小为1。其他任何大小都需要充分的理由和严格审查。
  • Goroutine生命周期: 绝不“启动即遗忘”。每个goroutine必须有可预测的停止时间或信号机制,且调用方必须能够等待其完成。
  • 禁止在init()中启动Goroutine:
    init()
    函数不得启动goroutine。通过带有显式生命周期方法的对象管理后台任务。
  • 原子操作: 使用
    go.uber.org/atomic
    进行类型安全的原子操作。

Data Integrity & Globals

数据完整性与全局变量

  • Copy Slices and Maps at Boundaries: Copy incoming slices/maps if you store them. Copy outgoing ones if they expose internal state.
  • Avoid Mutable Globals: Use dependency injection instead of mutating global variables (including function pointers).
  • No Shadowing: Do not use Go's predeclared identifiers (e.g.,
    error
    ,
    string
    ,
    make
    ,
    new
    ) as names.
    go vet
    should be clean.
  • 在边界处复制切片和映射: 如果要存储传入的切片/映射,请进行复制;如果传出的切片/映射会暴露内部状态,也请进行复制。
  • 避免可变全局变量: 使用依赖注入替代修改全局变量(包括函数指针)。
  • 禁止遮蔽标识符: 不要将Go的预声明标识符(如
    error
    string
    make
    new
    )用作名称。
    go vet
    检查应无问题。

Code Structure

代码结构

  • Consistency is Key: Above all, be consistent at the package level or higher.
  • Minimize
    init()
    :
    Avoid
    init()
    unless necessary and deterministic. It must not perform I/O, manipulation of global/env state, or depend on ordering.
  • Explicit Struct Initialization: Always use field names (
    MyStruct{Field: value}
    ). (Exception: test tables with <= 3 fields).
  • Nil Slice Semantics: Return
    nil
    for empty slices. Check
    len(s) == 0
    for emptiness.
    var
    declared slices are immediately usable.
  • 一致性是关键: 最重要的是,在包级别或更高层面保持一致性。
  • 尽量减少init()的使用: 除非必要且具有确定性,否则避免使用
    init()
    。它不得执行I/O操作、修改全局/环境状态,也不得依赖执行顺序。
  • 显式结构体初始化: 始终使用字段名进行初始化(
    MyStruct{Field: value}
    )。(例外:字段数≤3的测试表)。
  • 空切片语义: 空切片返回
    nil
    。通过
    len(s) == 0
    判断是否为空。使用
    var
    声明的切片可直接使用。

Expert Guidance

专家指导

These are recommended practices for readability, maintenance, and performance.
这些是针对可读性、可维护性和性能的推荐实践。

Pointers & Interfaces

指针与接口

  • No Interface Pointers: Pass interfaces as values. Use a pointer only if methods must modify the underlying data.
  • Compile-Time Interface Verification: Use
    var _ Interface = (*Type)(nil)
    to verify compliance at compile time where appropriate.
  • Receiver Choice: Pointer receivers are only for pointers or addressable values. Value receivers work for both. Interfaces can be satisfied by pointers even for value receivers.
  • 禁止使用接口指针: 接口按值传递。仅当方法必须修改底层数据时才使用指针。
  • 编译时接口验证: 必要时使用
    var _ Interface = (*Type)(nil)
    在编译时验证接口合规性。
  • 接收器选择: 指针接收器仅适用于指针或可寻址值。值接收器对两者都适用。即使是值接收器,指针也可以满足接口要求。

Concurrency & Synchronization

并发与同步

  • Zero-Value Mutexes:
    sync.Mutex
    and
    sync.RWMutex
    are valid in their zero-value state. Do not use pointers to mutexes. Use non-pointer fields in structs.
  • No Mutex Embedding: Do not embed mutexes in structs, even unexported ones.
  • Synchronization: Use
    sync.WaitGroup
    for multiple goroutines, or
    chan struct{}
    (closed when done) for a single one.
  • 零值互斥锁:
    sync.Mutex
    sync.RWMutex
    的零值状态有效。不要使用互斥锁的指针。在结构体中使用非指针字段。
  • 禁止嵌入互斥锁: 不要在结构体中嵌入互斥锁,即使是未导出的也不行。
  • 同步: 多个goroutine使用
    sync.WaitGroup
    ,单个goroutine使用
    chan struct{}
    (完成时关闭)。

Time Management

时间管理

  • time
    Package:
    Always use the
    "time"
    package for all time operations.
  • Instants vs. Periods: Use
    time.Time
    for instants and
    time.Duration
    for periods.
  • External Systems: Use
    time.Time
    /
    time.Duration
    with external systems. If not possible, use
    int
    /
    float64
    with unit in the name (e.g.,
    Millis
    ), or RFC 3339 strings for timestamps.
  • Comparison: Use
    .AddDate
    for calendar days,
    .Add
    for absolute 24-hour periods.
  • time
    包:
    所有时间操作均使用
    "time"
    包。
  • 时刻与周期: 使用
    time.Time
    表示时刻,
    time.Duration
    表示周期。
  • 外部系统: 与外部系统交互时使用
    time.Time
    /
    time.Duration
    。如果无法实现,使用带单位名称的
    int
    /
    float64
    (如
    Millis
    ),或使用RFC 3339字符串作为时间戳。
  • 比较: 计算日历天数使用
    .AddDate
    ,计算绝对24小时周期使用
    .Add

Performance (Hot Path Only)

性能(仅针对热点路径)

  • strconv
    over
    fmt
    :
    Use
    strconv
    for primitive-to-string conversions.
  • String-to-Byte: Convert fixed strings to
    []byte
    once and reuse.
  • Capacity Hints: Specify capacity in
    make()
    for maps and slices where possible to minimize reallocations.
  • 优先使用strconv而非fmt: 基本类型与字符串的转换使用
    strconv
  • 字符串转字节: 固定字符串转换为
    []byte
    后复用。
  • 容量提示: 可能的话,在
    make()
    中指定映射和切片的容量,以减少重新分配。

Code Style & Readability

代码风格与可读性

  • Line Length: Soft limit of 99 characters. Avoid horizontal scrolling.
  • Grouping: Group related
    import
    ,
    const
    ,
    var
    , and
    type
    declarations. Group variables in functions if declared adjacently.
  • Import Ordering: Two groups: Standard library first, then others, separated by a blank line.
  • Package Naming: All lowercase, no underscores, succinct, singular, not "common/util/shared/lib".
  • Function Naming: MixedCaps. Underscores allowed in tests for grouping.
  • Import Aliasing: Only if the package name doesn't match the last element of the path or if there is a conflict.
  • Ordering: Group by receiver. Sort by call order. Exported functions first. Utilities at the end.
  • Nesting: Handle error/special cases first (early return/continue).
  • Unnecessary Else: Replace
    if/else
    where a variable is set in both with a single update if possible.
  • Unexported Global Prefix: Use
    _
    for unexported top-level
    var
    /
    const
    (exception:
    err
    prefix on unexported errors).
  • Embedding: Place at the top of the struct, separated by a blank line. Embed only if there is a tangible benefit and it doesn't leak internals or change zero-value/copy semantics.
  • Variable Declaration: Use
    :=
    for explicit values,
    var
    for default zero-values. Minimize scope.
  • Naked Parameters: Use C-style comments
    /* paramName */
    for clarity. Use custom types instead of
    bool
    where appropriate.
  • Raw Strings: Use backticks (
    `
    ) for multi-line or quoted strings.
  • 行长度: 软限制为99个字符,避免水平滚动。
  • 分组: 相关的
    import
    const
    var
    type
    声明分组。函数中相邻声明的变量也分组。
  • 导入顺序: 分为两组:标准库在前,其他在后,用空行分隔。
  • 包命名: 全小写,无下划线,简洁,单数形式,不要使用"common/util/shared/lib"这类名称。
  • 函数命名: 使用驼峰式命名。测试函数中可使用下划线进行分组。
  • 导入别名: 仅当包名与路径最后部分不匹配或存在冲突时使用。
  • 排序: 按接收器分组,按调用顺序排序。导出函数在前,工具函数在后。
  • 嵌套: 先处理错误/特殊情况(提前返回/继续)。
  • 不必要的Else: 如果if/else中都设置同一个变量,尽可能替换为单次赋值。
  • 未导出全局变量前缀: 未导出的顶层
    var
    /
    const
    使用
    _
    作为前缀(例外:未导出错误使用
    err
    前缀)。
  • 嵌入: 放在结构体顶部,用空行分隔。仅当有实际好处且不会暴露内部状态或改变零值/复制语义时才使用嵌入。
  • 变量声明: 有明确值时使用
    :=
    ,默认零值时使用
    var
    。尽量缩小作用域。
  • 匿名参数: 使用C风格注释
    /* paramName */
    提高清晰度。必要时使用自定义类型替代
    bool
  • 原始字符串: 多行或带引号的字符串使用反引号(
    `
    )。

Patterns

模式

  • Table-Driven Tests: Use the
    tests
    slice and
    tt
    case variable. Use
    give
    /
    want
    prefixes. Avoid complex logic inside subtests.
  • Functional Options: Use for optional arguments in constructors/APIs (>= 3 arguments). Use an
    Option
    interface and an unexported
    options
    struct.
  • 表驱动测试: 使用
    tests
    切片和
    tt
    测试用例变量。使用
    give
    /
    want
    前缀。避免在子测试中编写复杂逻辑。
  • 函数式选项: 构造函数/API的可选参数(≥3个参数)使用此模式。使用
    Option
    接口和未导出的
    options
    结构体。

Tooling & Verification

工具与验证

  • Tooling (Go 1.24+): Prefer
    go tool <toolname>
    for invoking project-local tools.
  • Linting: Use
    golangci-lint
    as the runner. Use the configuration in assets/.golangci.yml as a baseline.
  • Struct Tags: Always use field tags for marshaled structs (JSON, YAML).
  • Leak Detection: Use
    go.uber.org/goleak
    for goroutine leaks.
  • Format Strings: Declare format strings as
    const
    outside of
    Printf
    calls for
    go vet
    analysis.
  • Printf Naming: End custom Printf-style functions with
    f
    .
  • 工具(Go 1.24+): 优先使用
    go tool <toolname>
    调用项目本地工具。
  • 代码检查: 使用
    golangci-lint
    作为检查器,以assets/.golangci.yml中的配置为基线。
  • 结构体标签: 序列化的结构体(JSON、YAML)始终使用字段标签。
  • 泄漏检测: 使用
    go.uber.org/goleak
    检测goroutine泄漏。
  • 格式化字符串: 将格式化字符串声明为
    const
    ,放在
    Printf
    调用之外,以便
    go vet
    分析。
  • Printf命名: 自定义的Printf风格函数以
    f
    结尾。",