陷阱 | 描述 | 正确的做法 |
---|---|---|
忽略错误 | 忽略返回的错误可能会导致意外行为并使调试变得困难。 | 始终立即检查并处理错误。使用有意义的错误消息。 |
资源泄漏 | 不关闭文件句柄或 HTTP 响应正文等资源可能会导致资源耗尽。 | 使用 确保资源正确关闭。 |
恐慌和恢复误用 | 使用 进行错误处理可能会导致崩溃和难以调试程序。 |
在真正特殊的情况下使用 。对可恢复的错误使用正确的错误处理。 |
并发问题 | goroutine 和通道使用不当可能会导致竞争条件和死锁。 | 使用同步原语( 、 、通道)来管理并发。 |
使用不当
|
不正确使用 可能会导致意外行为和资源泄漏。 |
在获取资源后立即放置 语句以确保其得到执行。 |
无视
|
忽略延迟函数中的 可能会导致程序崩溃。 |
在延迟函数中使用 来优雅地处理恐慌。 |
硬编码值 | 硬编码配置值会使代码不太灵活且更难以维护。 | 使用配置文件、环境变量或标志进行配置。 |
命名不一致 | 不一致的命名会使代码更难阅读和理解。 | 遵循 Go 命名约定:变量和函数采用驼峰命名法,首字母大写。 |
全局变量 | 使用全局变量可能会导致意外行为并使代码难以测试。 | 避免全局变量。使用依赖注入来传递所需的依赖项。 |
不使用
|
在长时间运行的操作中忽略 的使用可能会导致超时管理变得困难。 |
使用 处理超时、取消和截止日期。 |
忽略去看兽医 | 不使用 可能会导致代码中出现未被注意到的潜在问题。 |
定期运行 以发现常见错误并提高代码质量。 |
不使用
|
格式不一致会使代码难以阅读。 | 使用 根据 Go 标准自动格式化代码。 |
不必要地使用
|
过度使用 可能会导致类型断言问题和类型安全性降低。 |
尽可能使用特定类型。仅在绝对必要时使用 。 |
滥用
|
不正确地使用 可能会导致性能下降。 |
对于经常分配和释放的临时对象使用 。确保对象在重新使用之前重置。 |
只是在我的团队代码中发现了一堆错误......
1. Ignoring Errors
Pitfall:
go
out, _ := os.Create(fileName)
Correct:
go
out, err := os.Create(fileName)
if err != nil {
return fmt.Errorf("failed to create file %s: %w", fileName, err)
}
2. Resource Leaks
Pitfall:
go
resp, err := http.Get(url)
if err != nil {
return err
}
// resp.Body.Close() is missing
_, err = io.Copy(out, resp.Body)
Correct:
go
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
3. Panic and Recover Misuse
Pitfall:
go
if err != nil {
panic(err)
}
Correct:
go
if err != nil {
log.Fatalf("Fatal error: %s", err)
}
4. Concurrency Issues
Pitfall:
go
var counter int
go func() {
counter++
}()
Correct:
go
var mu sync.Mutex
var counter int
go func() {
mu.Lock()
defer mu.Unlock()
counter++
}()
5. Improper Use of defer
Pitfall:
go
f, err := os.Open(file)
if err != nil {
return err
}
processFile(f)
f.Close() // If processFile panics, this won't be called
Correct:
go
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()
processFile(f)
6. Ignoring recover
Pitfall:
go
func mightPanic() {
panic("something went wrong")
}
Correct:
go
func safeCall() {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from panic: %v", r)
}
}()
mightPanic()
}
7. Hardcoding Values
Pitfall:
go
port := "8080"
Correct:
go
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
8. Inconsistent Naming
Pitfall:
go
func Fetch_data() {}
Correct:
go
func fetchData() {}
9. Global Variables
Pitfall:
go
var config Config
Correct:
go
func main() {
config := loadConfig()
runApp(config)
}
10. Not Using context
Pitfall:
go
func fetchData() error {
// long running operation
}
Correct:
go
func fetchData(ctx context.Context) error {
// use ctx for cancellation and timeouts
}
11. Ignoring Go Vet
Pitfall:
go
// Not running go vet
Correct:
sh
go vet ./...
12. Not Using go fmt
Pitfall:
go
func main(){fmt.Println("Hello, world!")}
Correct:
go
func main() {
fmt.Println("Hello, world!")
}
13. Using interface{} Unnecessarily
Pitfall:
go
func process(data interface{}) error {
// process data
}
Correct:
go
func process(data []byte) error {
// process data
}
14. Misusing sync.Pool
Pitfall:
go
var pool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
// Not resetting the buffer before putting it back
Correct:
go
var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset() // Reset before using
defer bufPool.Put(buf)
// Use buf
enter code here