Go Style 代码风格规范

Golang 代码 编程规范

Go 代码应该以最简单的方式编写,以实现其目标,无论是在行为还是性能方面。在 Google Go 代码库中,简单代码:

  • 从上到下都易于阅读;
  • 不假设你已经知道它在做什么;
  • 不假设你可以记住所有前面的代码;
  • 没有不必要的抽象层次;
  • 没有能引起关注的世俗名称;
  • 让开发者清楚地了解价值观和决策的传播;
  • 有注释解释代码为什么这样做,而不是做什么,以避免将来出现偏差;
  • 有独立的文档;
  • 有 有用的错误和有用的失败测试;
  • 可能经常与"聪明"的代码互相排斥。

参考指南:

1. gofmt 统一代码格式

执行 go fmt ./... 来统一代码格式。

2. 注释说明增强

在会引发歧义或者和上文判断不同时使用注释以提醒开发者。

golang 复制代码
if err := doSomething(); err != nil {
    // ...
}

if err := doSomething(); err == nil { // if NO error
    // ...
}
3. 注释应该说明的是"为什么",而不是"做什么"
go 复制代码
// ❌ Bad
// Increment i by 1
i = i + 1

// ✅ Good
// Retry count is increased after each failed attempt.
i++
4. 当有 context.Context 参数时,其永远是方法的第一个参数并且不被放在结构体中
golang 复制代码
// ❌ Bad
type ServerContext struct {
  ctx context.Context
  // other 
}

func (s *ServerContext) doSomething(param any, ctx context.Context) {
  // ...
}

// ✅ Good
type ServerContext struct {
  // other 
}

func (s *ServerContext) doSomething(ctx context.Context, param any) {
  // ...
}
5. 正确声明变量
golang 复制代码
// ❌ Bad
// nil 
s := []int8{}

// ✅ Good
// 非零但长度为零
var s []int

i := 42

\[\]T{} 会默认分配内存,var s \[\]T 更清晰与高效。

在使用非零值初始化时,使用 := 赋值。

6. 代码中不要出现 panic
golang 复制代码
// ❌ Bad
func ParseConfig(file *os.File, cfg any) {
    decoder := yaml.NewDecoder(file)
    if err := decoder.Decode(cfg); err != nil {
        panic("failed to decode config: " + err.Error())
    }
}

// ✅ Good
func Parse(file *os.File, cfg any) error {
    decoder := yaml.NewDecoder(file)
    if err := decoder.Decode(cfg); err != nil {
        return err
    }
    return nil
}

依赖库应该优先返回 err,而不是终止程序。

7. 保持错误信息干净,使用结构化日志
golang 复制代码
// ❌ Bad
return fmt.Errorf("some error.")

// ✅ Good
return fmt.Errorf("some error.")

error msg 小写开头且不以任何标点结尾。

8. 避免多余的 else 逻辑
golang 复制代码
// ❌ Bad
if err != nil {
    if something {
        return err
    }
} else {
    doSomething()
}

// ✅ Good
if err != nil {
    return err
}
doSomething()

尽早返回 error 且避免多余的 else 语句。

9. 使用包别名导入

除非为了避免名称冲突,否则应避免重命名导入;好的包名称不应该需要重命名。如果发生冲突,优先重命名本地或项目特定的导入。

import pkg 按组组织,每组之间以空行分隔。标准库包始终位于第一组,其次是第三方包,最后是项目内部包。

10. 缩写保持大写和官方库一致
golang 复制代码
// ❌ Bad
type HttpServer struct{}

// ✅ Good
type HTTPServer struct{}

标准库写法:HTTP、ID、JSON。保持一致性.

11. 避免裸返回
golang 复制代码
// ❌ Bad
func sum(a, b int) (result int) {
    result = a + b
    return
}

// ✅ Good
func sum(a, b int) int {
    return a + b
}

除非函数非常短,一眼看到底时使用裸返回。

12. 包名、接受者名保持简单与简洁切避免函数名重复与啰嗦
golang 复制代码
// ❌ Bad
package my_utils

func (this *Server) Start() {}

package yamlconfig
func ParseYAMLConfig(input string) (*Config, error)

func OverrideFirstWithSecond(dest, source *Config) error

// 不应书写函数的返回参数名,这会导致 goDoc 混乱
func doSomething(a, b int) (sum int, err error) {
  // logic
}

// ✅ Good
package utils

func (s *Server) Start() 

package yamlconfig
func Parse(input string) (*Config, error)

func Override(dest, source *Config) error

func doSomething(a, b int) (int,error) {
  // logic
}
  • 包名小写、简洁、无下划线;
  • 接受者变量 s, r, c 这种短变量常见且清晰;
  • 包名提供上下文。

当需要消除类似名称的函数歧义时,可以包含额外的信息。

golang 复制代码
// ✅ Good
func (c *Config) WriteTextTo(w io.Writer) (int64, error)
func (c *Config) WriteBinaryTo(w io.Writer) (int64, error)
13. 函数名中不应出现返回类型且命名体现语义
golang 复制代码
// ❌ Bad
func TransformToJSON(input *Config) *jsonconfig.Config

func (c *Config) GetJobName(key string) (value string, ok bool)

// ✅ Good
func Transform(input *Config) *jsonconfig.Config

// 返回值函数中不要动词
func (c *Config) JobName(key string) (value string, ok bool)

// 动作用动词,取值用名词
func (c *Config) ApplyChanges() error
func ProcessData(data []byte) error

动作用动词,取值用名词且返回值函数中不要动词。

14. 测试写法符合 Go got %v, want %v风格
golang 复制代码
// ❌ Bad
if got != want {
    t.Errorf("expected %v but got %v", want, got)
}

// ✅ Good
if got != want {
    t.Errorf("got %v, want %v", got, want)
}
15. 常量与结构化错误声明
golang 复制代码
type Animal string

var (
    // ErrDuplicate occurs if this animal has already been seen.
    ErrDuplicate = errors.New("duplicate")

    // ErrMarsupial occurs because we're allergic to marsupials outside Australia.
    // Sorry.
    ErrMarsupial = errors.New("marsupials are not supported")
)

func process(animal Animal) error {
    switch {
    case seen[animal]:
        return ErrDuplicate
    case marsupial(animal):
        return ErrMarsupial
    }
    seen[animal] = true
    // ...
    return nil
}

在使用到常量定义或者错误时,将其机构化定义在文件顶部或统一管理。

16. 当函数参数列表过多时,使用可变参数处理输入
golang 复制代码
type SshProtocol struct {
	Host                 string
	Port                 string
	Timeout              string
	Username             string
	Password             string
	PrivateKey           string
	PrivateKeyPassphrase string
	ReuseConnection      string
	Script               string
	ParseType            string
	ProxyHost            string
	ProxyPort            string
	ProxyUsername        string
	ProxyPassword        string
	UseProxy             string
	ProxyPrivateKey      string
}

type SshProtocolConfigOptFunc func(option *SshProtocol)

func NewSshProtocol(host, port string, opts ...SshProtocolConfigOptFunc) *SshProtocol {

	option := &SshProtocol{
		Host: host,
		Port: port,
	}

	for _, opt := range opts {
		opt(option)
	}

	return &SshProtocol{
		Host:                 host,
		Port:                 port,
		Timeout:              option.Timeout,
		Username:             option.Username,
		Password:             option.Password,
		PrivateKey:           option.PrivateKey,
		PrivateKeyPassphrase: option.PrivateKeyPassphrase,
		ReuseConnection:      option.ReuseConnection,
		Script:               option.Script,
		ParseType:            option.ParseType,
		ProxyHost:            option.ProxyHost,
		ProxyPort:            option.ProxyPort,
		ProxyUsername:        option.ProxyUsername,
		ProxyPassword:        option.ProxyPassword,
		UseProxy:             option.UseProxy,
		ProxyPrivateKey:      option.ProxyPrivateKey,
	}
}

func (sp *SshProtocol) IsInvalid() error {

	return nil
}
17. 字符串拼接
golang 复制代码
// 连接少量字符时使用 + 
key := "projectid: " + p

// 构建带有格式化的复杂字符串时,优先使用 fmt.Sprintf
str := fmt.Sprintf("%s [%s:%d]-> %s", src, qos, mtu, dst)

// 字符串格式更加复杂时,优先使用 text/template 或 safehtml/template
相关推荐
Scene21610 分钟前
AgentScope 2.0:2. 快速上手 从零构建生产级智能体
后端
前端一课16 分钟前
用 TRAE Work 把项目踩坑经验沉淀成「团队可复用工程规范」,新人再也不重复掉坑
前端·后端
神奇小汤圆24 分钟前
一文吃透 Spring 框架:原理、实践与面试全解析
后端
站大爷IP26 分钟前
Python 的切片把我坑惨了,原来 `[:]` 是浅拷贝,而 `copy.deepcopy` 才是我的救命稻草
后端
神奇小汤圆28 分钟前
Java 万字长文:从零基础到高级应用的完整教程——把面向对象讲透
后端
孓最求完美30 分钟前
实战经验:JT808/JT809 车联网高并发服务端性能优化指南
后端
shengjk134 分钟前
深度拆解:从 LC-3 汇编到 Java/Rust,数组越界与硬件中断的底层真相
后端
Gorway36 分钟前
理解 Spring 依赖注入:从构造器注入到集合与条件 Bean
java·后端
颜进强1 小时前
Claude Code - 26 效率三件套:cc-switch 切模型 · codeburn 算成本 · claude-hud 看状态
前端·后端·ai编程