golang-style

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Go Coding Conventions

Go 编码规范

Follow these conventions strictly when writing Go code.
编写Go代码时请严格遵循以下规范。

Happy Path Coding

快乐路径编码

Structure code so the successful path flows straight down. Handle errors immediately, then continue with main logic.
go
// Correct: happy path flows down.
func ProcessUser(id string) (*User, error) {
    user, err := db.GetUser(id)
    if err != nil {
        return nil, fmt.Errorf("get user %s: %w", id, err)
    }

    if err := user.Validate(); err != nil {
        return nil, fmt.Errorf("validate user %s: %w", id, err)
    }

    return user, nil
}

// Wrong: main logic nested inside conditions.
func ProcessUser(id string) (*User, error) {
    user, err := db.GetUser(id)
    if err == nil {
        if err := user.Validate(); err == nil {
            return user, nil
        } else {
            return nil, err
        }
    }
    return nil, err
}
代码结构应让成功路径自上而下直线执行。立即处理错误,然后继续主逻辑。
go
// Correct: happy path flows down.
func ProcessUser(id string) (*User, error) {
    user, err := db.GetUser(id)
    if err != nil {
        return nil, fmt.Errorf("get user %s: %w", id, err)
    }

    if err := user.Validate(); err != nil {
        return nil, fmt.Errorf("validate user %s: %w", id, err)
    }

    return user, nil
}

// Wrong: main logic nested inside conditions.
func ProcessUser(id string) (*User, error) {
    user, err := db.GetUser(id)
    if err == nil {
        if err := user.Validate(); err == nil {
            return user, nil
        } else {
            return nil, err
        }
    }
    return nil, err
}

Error Wrapping

错误包装

Always wrap errors with context using
%w
. Include the operation and relevant identifiers.
go
// Correct: wrapped with context.
if err != nil {
    return fmt.Errorf("create order for customer %s: %w", customerID, err)
}

// Wrong: no context.
if err != nil {
    return err
}
始终使用
%w
为错误添加上下文信息,包含操作内容和相关标识符。
go
// Correct: wrapped with context.
if err != nil {
    return fmt.Errorf("create order for customer %s: %w", customerID, err)
}

// Wrong: no context.
if err != nil {
    return err
}

Sentinel Errors

哨兵错误

Define package-level sentinel errors for expected error conditions. Use
errors.Is()
to check.
go
// Define at package level.
var (
    ErrNotFound     = errors.New("not found")
    ErrUnauthorized = errors.New("unauthorized")
    ErrInvalidInput = errors.New("invalid input")
)

// Return sentinel errors.
func GetUser(id string) (*User, error) {
    user := db.Find(id)
    if user == nil {
        return nil, ErrNotFound
    }
    return user, nil
}

// Check with errors.Is().
user, err := GetUser(id)
if errors.Is(err, ErrNotFound) {
    // Handle not found case.
}
为预期的错误场景定义包级别的哨兵错误,使用
errors.Is()
进行检查。
go
// Define at package level.
var (
    ErrNotFound     = errors.New("not found")
    ErrUnauthorized = errors.New("unauthorized")
    ErrInvalidInput = errors.New("invalid input")
)

// Return sentinel errors.
func GetUser(id string) (*User, error) {
    user := db.Find(id)
    if user == nil {
        return nil, ErrNotFound
    }
    return user, nil
}

// Check with errors.Is().
user, err := GetUser(id)
if errors.Is(err, ErrNotFound) {
    // Handle not found case.
}

Comments

注释规范

All comments end with a period.
go
// ProcessOrder handles order creation and validation.
func ProcessOrder(o *Order) error {
    // Validate the order before processing.
    if err := o.Validate(); err != nil {
        return err
    }
    // Continue with order processing.
    return nil
}
所有注释都应以句号结尾。
go
// ProcessOrder handles order creation and validation.
func ProcessOrder(o *Order) error {
    // Validate the order before processing.
    if err := o.Validate(); err != nil {
        return err
    }
    // Continue with order processing.
    return nil
}

Naming Conventions

命名规范

Never use Go's predeclared identifiers as variable or parameter names. These include built-in functions and constants that can be shadowed but should not be.
go
// Wrong: shadows built-in identifiers.
func process(new string, len int, make bool) error {
    copy := "data"
    return nil
}

// Correct: use descriptive names instead.
func process(name string, length int, shouldCreate bool) error {
    dataCopy := "data"
    return nil
}
Predeclared identifiers to avoid:
  • Functions:
    new
    ,
    make
    ,
    len
    ,
    cap
    ,
    append
    ,
    copy
    ,
    delete
    ,
    close
    ,
    panic
    ,
    recover
    ,
    print
    ,
    println
    ,
    complex
    ,
    real
    ,
    imag
    ,
    clear
    ,
    min
    ,
    max
  • Constants:
    true
    ,
    false
    ,
    iota
    ,
    nil
  • Types:
    error
    ,
    bool
    ,
    string
    ,
    int
    ,
    int8
    ,
    int16
    ,
    int32
    ,
    int64
    ,
    uint
    ,
    uint8
    ,
    uint16
    ,
    uint32
    ,
    uint64
    ,
    uintptr
    ,
    float32
    ,
    float64
    ,
    complex64
    ,
    complex128
    ,
    byte
    ,
    rune
    ,
    any
    ,
    comparable
切勿将Go的预声明标识符用作变量或参数名称。这些包括可以被遮蔽但不应被遮蔽的内置函数和常量。
go
// Wrong: shadows built-in identifiers.
func process(new string, len int, make bool) error {
    copy := "data"
    return nil
}

// Correct: use descriptive names instead.
func process(name string, length int, shouldCreate bool) error {
    dataCopy := "data"
    return nil
}
需避免的预声明标识符:
  • 函数:
    new
    ,
    make
    ,
    len
    ,
    cap
    ,
    append
    ,
    copy
    ,
    delete
    ,
    close
    ,
    panic
    ,
    recover
    ,
    print
    ,
    println
    ,
    complex
    ,
    real
    ,
    imag
    ,
    clear
    ,
    min
    ,
    max
  • 常量:
    true
    ,
    false
    ,
    iota
    ,
    nil
  • 类型:
    error
    ,
    bool
    ,
    string
    ,
    int
    ,
    int8
    ,
    int16
    ,
    int32
    ,
    int64
    ,
    uint
    ,
    uint8
    ,
    uint16
    ,
    uint32
    ,
    uint64
    ,
    uintptr
    ,
    float32
    ,
    float64
    ,
    complex64
    ,
    complex128
    ,
    byte
    ,
    rune
    ,
    any
    ,
    comparable

Line Length

行长度限制

Maximum line length is 120 characters. Break long lines at logical points.
go
// Correct: break at logical points.
func ProcessOrderWithValidation(
    ctx context.Context,
    order *Order,
    validator OrderValidator,
) (*Result, error) {
    return nil, fmt.Errorf(
        "process order %s for customer %s: %w",
        order.ID,
        order.CustomerID,
        err,
    )
}
最大行长度为120个字符。在逻辑断点处拆分长行。
go
// Correct: break at logical points.
func ProcessOrderWithValidation(
    ctx context.Context,
    order *Order,
    validator OrderValidator,
) (*Result, error) {
    return nil, fmt.Errorf(
        "process order %s for customer %s: %w",
        order.ID,
        order.CustomerID,
        err,
    )
}

Documentation Lookup

文档查询

Use
go doc
to look up standard library and package documentation:
bash
go doc fmt.Errorf
go doc errors.Is
go doc context
使用
go doc
查询标准库和包的文档:
bash
go doc fmt.Errorf
go doc errors.Is
go doc context

Einride

Einride 专属规范

If the project is under the Einride organization, always use the Makefiles in the project which are generated by Sage (the
.sage
folder).
如果项目属于Einride组织,请始终使用项目中由Sage(.sage文件夹)生成的Makefile文件。