这里列出了 Go 中的常见陷阱及其描述以及解决这些陷阱的正确方法

问题描述 投票:0回答:1
陷阱 描述 正确的做法
忽略错误 忽略返回的错误可能会导致意外行为并使调试变得困难。 始终立即检查并处理错误。使用有意义的错误消息。
资源泄漏 不关闭文件句柄或 HTTP 响应正文等资源可能会导致资源耗尽。 使用
defer
确保资源正确关闭。
恐慌和恢复误用 使用
panic
进行错误处理可能会导致崩溃和难以调试程序。
在真正特殊的情况下使用
panic
。对可恢复的错误使用正确的错误处理。
并发问题 goroutine 和通道使用不当可能会导致竞争条件和死锁。 使用同步原语(
sync.Mutex
sync.WaitGroup
、通道)来管理并发。
使用不当
defer
不正确使用
defer
可能会导致意外行为和资源泄漏。
在获取资源后立即放置
defer
语句以确保其得到执行。
无视
recover
忽略延迟函数中的
recover
可能会导致程序崩溃。
在延迟函数中使用
recover
来优雅地处理恐慌。
硬编码值 硬编码配置值会使代码不太灵活且更难以维护。 使用配置文件、环境变量或标志进行配置。
命名不一致 不一致的命名会使代码更难阅读和理解。 遵循 Go 命名约定:变量和函数采用驼峰命名法,首字母大写。
全局变量 使用全局变量可能会导致意外行为并使代码难以测试。 避免全局变量。使用依赖注入来传递所需的依赖项。
不使用
context
在长时间运行的操作中忽略
context
的使用可能会导致超时管理变得困难。
使用
context
处理超时、取消和截止日期。
忽略去看兽医 不使用
go vet
可能会导致代码中出现未被注意到的潜在问题。
定期运行
go vet
以发现常见错误并提高代码质量。
不使用
go fmt
格式不一致会使代码难以阅读。 使用
go fmt
根据 Go 标准自动格式化代码。
不必要地使用
interface{}
过度使用
interface{}
可能会导致类型断言问题和类型安全性降低。
尽可能使用特定类型。仅在绝对必要时使用
interface{}
滥用
sync.Pool
不正确地使用
sync.Pool
可能会导致性能下降。
对于经常分配和释放的临时对象使用
sync.Pool
。确保对象在重新使用之前重置。

只是在我的团队代码中发现了一堆错误......

go
1个回答
0
投票
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
© www.soinside.com 2019 - 2024. All rights reserved.