Go 开发规范1
Go 开发规范,包含基本开发规范、多线程、高并发和事务处理,并为每个规范提供正确和错误实例:
一、基本开发规范
1. 命名规范
规范:包名使用小写单字,变量 / 函数采用驼峰命名(导出成员首字母大写),常量使用全大写 + 下划线。
正确示例:
// 包名:小写单字
package user
// 导出函数:首字母大写
func GetUserByID(id int64) (*User, error) { ... }
// 非导出变量:首字母小写
var maxRetries = 3
// 常量:全大写+下划线
const MAX_CONN = 100
// 接口名:以er结尾
type Reader interface {
Read() ([]byte, error)
}
错误示例:
// 错误:包名使用复数和下划线
package users_info
// 错误:导出函数首字母小写
func get_user_by_id(id int64) (*User, error) { ... }
// 错误:常量使用驼峰
const maxConn = 100
// 错误:接口名不以er结尾
type ReadInterface interface { ... }
2. 代码格式
规范 :使用gofmt
自动格式化,左括号与关键字同行,每行不超过 80 字符。
正确示例:
if err != nil {
return nil, err
}
// 长参数换行
result, err := query(
ctx,
"SELECT id, name, email FROM users WHERE age > ?",
18,
)
错误示例:
// 错误:左括号另起一行
if err != nil
{
return nil, err
}
// 错误:超长行未拆分
result, err := query(ctx, "SELECT id, name, email, phone, address, created_at, updated_at FROM users WHERE age > ? AND status = ?", 18, "active")
3. 错误处理
规范 :必须检查错误,使用%w
包装错误,禁止忽略错误,业务错误返回error
而非panic
。
正确示例:
// 正确:检查并包装错误
user, err := getUser(id)
if err != nil {
return nil, fmt.Errorf("failed to get user: %w", err)
}
// 正确:自定义业务错误
var ErrUserNotFound = errors.New("user not found")
错误示例:
// 错误:忽略错误
user,_ := getUser(id) // 禁止使用_忽略错误
// 错误:用panic处理业务错误
if user == nil {
panic("user not found") // 业务错误不应panic
}
// 错误:未包装错误,丢失上下文
user, err := getUser(id)
if err != nil {
return nil, err // 应添加上下文说明
}
4. 包管理
规范:使用 Go Modules,避免循环依赖,依赖版本使用语义化版本。
正确示例:
// go.mod 正确示例
module example.com/user-service
go 1.20
require (
github.com/gin-gonic/gin v1.9.1
gorm.io/gorm v1.25.3
)
错误示例:
// 错误:依赖使用master分支
require (
github.com/gin-gonic/gin master // 应使用具体版本
)
// 错误:存在循环依赖(package A依赖B,B依赖A)
二、多线程(Goroutine)规范
1. Goroutine 管理
规范 :启动 goroutine 必须有退出机制,避免泄露;传递context
控制生命周期。
正确示例:
// 正确:使用context控制退出
func startWorker(ctx context.Context) {
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("worker exit")
return
case task := <-taskChan:
process(task)
}
}
}()
}
错误示例:
// 错误:无退出机制,goroutine泄露
func startWorker() {
go func() {
for {
task := <-taskChan // 当taskChan关闭后会永久阻塞
process(task)
}
}()
}
// 错误:循环中无限制创建goroutine
for_, task := range tasks {
go process(task) // 任务过多时会耗尽资源
}
2. 同步与通信
规范 :通过channel
通信共享数据,而非共享内存;必要时使用sync.Mutex
。
正确示例:
// 正确:用channel传递数据
func main() {
ch := make(chan int)
go func() {
ch <- calculate() // 发送结果
}()
result := <-ch // 接收结果
}
// 正确:使用Mutex保护共享变量
var count int
var mu sync.Mutex
func increment() {
mu.Lock()
defer mu.Unlock()
count++
}
错误示例:
// 错误:无同步机制共享变量
var count int
func increment() {
count++ // 并发修改会导致数据竞争
}
// 错误:过度使用共享内存
var data int
go func() { data = 10 }()
time.Sleep(100ms) // 依赖睡眠同步,不可靠
fmt.Println(data)
三、高并发规范
1. 资源控制
规范 :限制并发数(如使用工作池),避免资源耗尽;使用sync.Pool
缓存临时对象。
正确示例:
// 正确:使用工作池限制并发
func processTasks(tasks []Task) {
const workerCount = 10
ch := make(chan Task, len(tasks))
// 填充任务
for_, t := range tasks {
ch <- t
}
close(ch)
// 启动固定数量的worker
var wg sync.WaitGroup
for i := 0; i < workerCount; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for t := range ch {
process(t)
}
}()
}
wg.Wait()
}
// 正确:使用sync.Pool缓存对象
var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func handle() {
buf := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buf) // 归还
buf.Reset() // 重置状态
// 使用buf...
}
错误示例:
// 错误:无限制并发
func processTasks(tasks []Task) {
var wg sync.WaitGroup
for _, t := range tasks {
wg.Add(1)
go func(t Task) { // 任务过多时创建大量goroutine
defer wg.Done()
process(t)
}(t)
}
wg.Wait()
}
// 错误:频繁创建临时对象
func handle() {
for i := 0; i < 1000; i++ {
buf := new(bytes.Buffer) // 高并发下导致大量GC
// 使用buf...
}
}
2. 超时控制
规范 :所有 IO 操作(网络、数据库)必须设置超时;使用context.WithTimeout
控制。
正确示例:
// 正确:HTTP请求设置超时
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := http.DefaultClient.Do(req)
// 正确:数据库查询设置超时
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
var user User
err := db.WithContext(ctx).First(&user, id).Error
错误示例:
// 错误:无超时设置,可能永久阻塞
resp, err := http.Get(url) // 无超时,网络异常时永远等待
// 错误:超时后未释放资源
ctx,_ := context.WithTimeout(context.Background(), 5*time.Second)
req,_ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp,_ := http.DefaultClient.Do(req)
// 未调用cancel(),可能导致资源泄露
四、事务处理规范
1. 事务管理
规范:事务必须有明确的提交 / 回滚逻辑;避免在事务中执行耗时操作。
正确示例:
// 正确:GORM事务示例
tx := db.Begin()
if tx.Error != nil {
return err
}
// 操作1
if err := tx.Create(&user).Error; err != nil {
tx.Rollback() // 出错回滚
return err
}
// 操作2
if err := tx.Create(&order).Error; err != nil {
tx.Rollback() // 出错回滚
return err
}
// 全部成功提交
if err := tx.Commit().Error; err != nil {
return err
}
错误示例:
// 错误:未处理事务错误
tx := db.Begin()
tx.Create(&user)
tx.Create(&order)
tx.Commit() // 若中间操作失败,仍会提交部分数据
// 错误:事务中执行耗时操作
tx := db.Begin()
createUser(tx)
time.Sleep(5 * time.Second) // 长时间阻塞事务
createOrder(tx) // 可能导致锁竞争和超时
tx.Commit()
2. 事务隔离
规范:根据业务需求设置合适的隔离级别;避免长事务持有锁。
正确示例:
// 正确:设置事务隔离级别(MySQL)
tx := db.BeginTx(ctx, &sql.TxOptions{
Isolation: sql.LevelReadCommitted, // 读已提交
})
// 正确:短事务设计
tx.Begin()
// 仅包含必要的数据库操作
tx.Create(&user)
tx.Create(&order)
tx.Commit() // 快速提交释放锁
错误示例:
// 错误:使用默认隔离级别(可能不符合业务需求)
tx := db.Begin() // 未指定隔离级别,依赖数据库默认设置
// 错误:长事务持有锁
tx.Begin()
createUser(tx)
sendEmail() // 耗时的外部操作,导致事务长时间未提交
createOrder(tx)
tx.Commit() // 锁持有时间过长,引发并发问题
总结
以上规范覆盖了 Go 开发的核心场景,通过遵循这些规范并参考正确 / 错误实例,可以显著提升代码质量、可维护性和系统稳定性。实际开发中,建议结合静态检查工具(如golint
、staticcheck
)和 CI 流程强制执行规范。