Loading...
Loading...
Compare original and translation side by side
Normative: Required per Google's canonical Go style guide.
规范要求:需遵循Google官方Go语言风格指南。
errorerrorerrorerror// Good:
func Good() error { /* ... */ }
func GoodLookup() (*Result, error) {
// ...
if err != nil {
return nil, err
}
return res, nil
}nil// Bad: Concrete error type can cause subtle bugs
func Bad() *os.PathError { /*...*/ }
// Good: Always return the error interface
func Good() error { /*...*/ }errorerror// Good:
func Good() error { /* ... */ }
func GoodLookup() (*Result, error) {
// ...
if err != nil {
return nil, err
}
return res, nil
}nil// Bad: Concrete error type can cause subtle bugs
func Bad() *os.PathError { /*...*/ }
// Good: Always return the error interface
func Good() error { /*...*/ }context.Contexterrorcontext.ContexterrorNormative: Required per Google's canonical Go style guide.
// Bad:
err := fmt.Errorf("Something bad happened.")
// Good:
err := fmt.Errorf("something bad happened")// Good:
log.Infof("Operation aborted: %v", err)
log.Errorf("Operation aborted: %v", err)
t.Errorf("Op(%q) failed unexpectedly; err=%v", args, err)规范要求:需遵循Google官方Go语言风格指南。
// Bad:
err := fmt.Errorf("Something bad happened.")
// Good:
err := fmt.Errorf("something bad happened")// Good:
log.Infof("Operation aborted: %v", err)
log.Errorf("Operation aborted: %v", err)
t.Errorf("Op(%q) failed unexpectedly; err=%v", args, err)Normative: Required per Google's canonical Go style guide.
_log.Fatalpanic规范要求:需遵循Google官方Go语言风格指南。
_log.Fatalpanic// Good:
var b *bytes.Buffer
n, _ := b.Write(p) // never returns a non-nil error// Good:
var b *bytes.Buffer
n, _ := b.Write(p) // never returns a non-nil errorerrgroup// Good: errgroup handles cancellation and first-error semantics
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error { return task1(ctx) })
g.Go(func() error { return task2(ctx) })
if err := g.Wait(); err != nil {
return err
}errgroup// Good: errgroup handles cancellation and first-error semantics
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error { return task1(ctx) })
g.Go(func() error { return task2(ctx) })
if err := g.Wait(); err != nil {
return err
}Normative: Required per Google's canonical Go style guide.
-1nil// Bad: In-band error value
// Lookup returns the value for key or -1 if there is no mapping for key.
func Lookup(key string) int
// Bad: Caller mistakes can attribute errors to wrong function
return Parse(Lookup(missingKey))// Good: Explicit error or ok value
func Lookup(key string) (value string, ok bool)
// Good: Forces caller to handle the error case
value, ok := Lookup(key)
if !ok {
return fmt.Errorf("no value for %q", key)
}
return Parse(value)Parse(Lookup(key))Lookup(key)规范要求:需遵循Google官方Go语言风格指南。
-1nil// Bad: In-band error value
// Lookup returns the value for key or -1 if there is no mapping for key.
func Lookup(key string) int
// Bad: Caller mistakes can attribute errors to wrong function
return Parse(Lookup(missingKey))// Good: Explicit error or ok value
func Lookup(key string) (value string, ok bool)
// Good: Forces caller to handle the error case
value, ok := Lookup(key)
if !ok {
return fmt.Errorf("no value for %q", key)
}
return Parse(value)Parse(Lookup(key))Lookup(key)Normative: Required per Google's canonical Go style guide.
// Good: Error handling first, normal code unindented
if err != nil {
// error handling
return // or continue, etc.
}
// normal code// Bad: Normal code hidden in else clause
if err != nil {
// error handling
} else {
// normal code that looks abnormal due to indentation
}规范要求:需遵循Google官方Go语言风格指南。
// Good: Error handling first, normal code unindented
if err != nil {
// error handling
return // or continue, etc.
}
// normal code// Bad: Normal code hidden in else clause
if err != nil {
// error handling
} else {
// normal code that looks abnormal due to indentation
}// Good: Declaration separate from error check
x, err := f()
if err != nil {
return err
}
// lots of code that uses x
// across multiple lines// Bad: Variable scoped to else block, hard to read
if x, err := f(); err != nil {
return err
} else {
// lots of code that uses x
// across multiple lines
}// Good: Declaration separate from error check
x, err := f()
if err != nil {
return err
}
// lots of code that uses x
// across multiple lines// Bad: Variable scoped to else block, hard to read
if x, err := f(); err != nil {
return err
} else {
// lots of code that uses x
// across multiple lines
}Advisory: Recommended best practice.
| Caller needs to match? | Message type | Use |
|---|---|---|
| No | static | |
| No | dynamic | |
| Yes | static | |
| Yes | dynamic | custom |
建议:推荐的最佳实践。
| 调用者是否需要匹配? | 消息类型 | 使用方式 |
|---|---|---|
| 否 | 静态 | |
| 否 | 动态 | |
| 是 | 静态 | |
| 是 | 动态 | 自定义 |
Advisory: Recommended best practice.
%v%w%v%werrors.Iserrors.As%w"context message: %w"err建议:推荐的最佳实践。
%v%w%v%werrors.Iserrors.As%w"context message: %w"errSource: Uber Go Style Guide
// Bad: Logs AND returns - causes noise in logs
u, err := getUser(id)
if err != nil {
log.Printf("Could not get user %q: %v", id, err)
return err // Callers will also log this!
}
// Good: Wrap and return - let caller decide how to handle
u, err := getUser(id)
if err != nil {
return fmt.Errorf("get user %q: %w", id, err)
}
// Good: Log and degrade gracefully (don't return error)
if err := emitMetrics(); err != nil {
// Failure to write metrics should not break the application
log.Printf("Could not emit metrics: %v", err)
}
// Continue execution...
// Good: Match specific errors, return others
tz, err := getUserTimeZone(id)
if err != nil {
if errors.Is(err, ErrUserNotFound) {
// User doesn't exist. Use UTC.
tz = time.UTC
} else {
return fmt.Errorf("get user %q: %w", id, err)
}
}来源:Uber Go风格指南
// Bad: Logs AND returns - causes noise in logs
u, err := getUser(id)
if err != nil {
log.Printf("Could not get user %q: %v", id, err)
return err // Callers will also log this!
}
// Good: Wrap and return - let caller decide how to handle
u, err := getUser(id)
if err != nil {
return fmt.Errorf("get user %q: %w", id, err)
}
// Good: Log and degrade gracefully (don't return error)
if err := emitMetrics(); err != nil {
// Failure to write metrics should not break the application
log.Printf("Could not emit metrics: %v", err)
}
// Continue execution...
// Good: Match specific errors, return others
tz, err := getUserTimeZone(id)
if err != nil {
if errors.Is(err, ErrUserNotFound) {
// User doesn't exist. Use UTC.
tz = time.UTC
} else {
return fmt.Errorf("get user %q: %w", id, err)
}
}| Pattern | Guidance |
|---|---|
| Return type | Always use |
| Error strings | Lowercase, no punctuation |
| Ignoring errors | Comment explaining why it's safe |
| In-band errors | Avoid; use multiple returns |
| Error flow | Handle errors first, no else clauses |
| Error type choice | Match needed + dynamic → custom type; static → sentinel |
| Sentinel errors | Use |
| %v vs %w | |
| %w placement | Always at the end: |
| Handle once | Choose ONE: return, log+degrade, or match+handle |
| Logging | Don't log and return; let caller decide |
| 模式 | 指导原则 |
|---|---|
| 返回类型 | 始终使用 |
| 错误字符串 | 小写开头,无标点符号 |
| 忽略错误 | 添加注释说明安全原因 |
| 带内错误 | 避免使用;使用多返回值 |
| 错误流程 | 先处理错误,不使用else分支 |
| 错误类型选择 | 需要匹配+动态→自定义类型;静态→哨兵错误 |
| 哨兵错误 | 使用 |
| %v vs %w | |
| %w放置位置 | 始终放在末尾: |
| 单次处理 | 选择一种方式:返回、记录+降级、匹配+处理 |
| 日志记录 | 不要同时记录和返回;让调用者决定 |