脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Golang - 从错误中学习改正Go语言五个坏习惯提高编程技巧

从错误中学习改正Go语言五个坏习惯提高编程技巧

2023-05-17 13:05Slagga Golang

这篇文章主要为大家介绍了从错误中学习改正Go语言五个坏习惯提高编程技巧示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

从他人的错误中学习,通过本指南避免常见陷阱和坏习惯,提高你的 Go 编程技巧

在 Go 语言中,就像在任何编程语言中一样,了解常见陷阱和坏习惯是编写干净、高效代码的关键。

尽管下面列出的某些做法通常被认为是不好的,但在某些情况下它们可以有效地使用。 这篇文章旨在提醒大家这些做法的问题所在,并教导如何避免这些陷阱。

让我们深入探讨。

1. 使用 init()

在 Go 中,init()函数是在主函数之前执行的特殊函数。

“如果在任何包中初始化是如此重要的过程,为什么在 Go 中init()被认为是一种不好的实践?” —— 读者

是的,虽然init()函数有助于在运行核心逻辑之前进行初始化,但它们的执行顺序可能难以理解。 这可能会导致关于初始化顺序的混乱。

如果两个模块互相依赖于初始化并位于不同的包中,则可能会增加复杂性并需要额外的代码添加等待逻辑。然而,这也可能导致死锁的可能性。

另一个init()函数的问题是它会使测试更加困难。因为它们自动运行,很难控制它们何时执行,这可能使设置测试用例和测试代码行为变得具有挑战性。

我遇到了一个问题,我的服务从部署状态到准备就绪需要 10 分钟的时间。我在主函数的第一行设置了断点,但它从未触发。

我们不得不调试所有的init()函数,发现一个队友在一个“我不记得的包”中使用了init()函数,从一个大文件加载了大量数据到内存中,这导致花费了很多时间追踪一个微小的问题。

2. 使用全局变量

这与使用单例模式时可能出现的问题类似,特别是当全局变量是复杂的,包含映射、切片或指针时。

  • 竞态条件(Race condition):当使用全局变量时,多个goroutine同时访问全局变量会导致意外行为。这在Go语言中是一个很大的问题。

  • 难以测试:使用全局变量会使你的项目更具状态,这意味着当你开始单元测试/集成测试时,全局变量必须与运行main()或生产环境时相同。

  • 不够模块化且难以重用:难以组织和封装数据,因为任何包或模块都可以访问它们。这可能会导致代码不够模块化,更难以理解,因为很难确定数据来自哪里以及如何使用它们。

通常建议封装您的包,使其可以在不影响其他包的情况下移动。使用全局变量可能会使您的代码更紧密耦合,更难以修改或重用。

3. 忽略错误消息

错误是Go编程的内在部分,处理它们以优雅的方式确保在发生错误时不会发生意外情况非常重要。

忽略错误消息的方法是使用“_”符号,这样做会丢弃函数返回的错误值,可能会导致意外行为。

检查错误并适当地处理它们以防止程序发生崩溃和崩溃非常重要。

?
1
2
3
4
5
6
7
8
9
10
11
12
// sample 1
func main() {
    var x interface{} = "hello"
    s := x.(int) // panic: interface conversion: interface {} is string, not int
    fmt.Println(s)
}
// sample 2
func main() {
    var x interface{} = "hello"
    s, _ := x.(int) // safe but DON'T
    fmt.Println(s)
}

忽略错误处理会导致生产代码中出现重大问题,因为这可能使得识别和修复错误变得困难。始终检查错误并适当地解决它们对于确保代码的顺畅运行非常重要。

4. GOTO语句 — 跳进陷阱

不仅在Go语言中,许多语言都认为使用“goto”语句是一种不良实践,因为它会使代码更难理解和维护。

原因是“goto”语句忽略了代码流程,使得在不引入错误的情况下难以理解代码的不同部分之间的依赖关系。

这可能会使得在运行时推理程序的状态变得困难,使得调试和测试变得更加困难。

使用“goto”可能会导致错误数量增加,使得更难以识别问题的根本原因。

5. 不使用Defer和Recover

利用“defer”和“recover”的主要原因是为了防止恐慌。“defer”甚至可以在发生恐慌时执行,而“recover”可以捕捉到恐慌,允许更加控制地处理意外情况。

这种使用方式被认为是不好的代码实践:

?
1
2
3
4
5
6
7
8
func readFile(filename string) {
    file, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    // Do something with the file
    file.Close() // <--- DONT
}

我们使用defer这种方式,这样即使readFile()函数出现panic,文件也会被关闭。此外,这样做也容易记住在open()函数之后立即放置关闭函数。

?
1
2
3
4
5
6
7
8
9
func readFile(filename string) {
    file, err := os.Open(filename)
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    // Do something with the file
    ...
}

6. 使用太多次的context.Background()

在 Go 中,上下文是最强大的功能之一。当正确使用时,它可以作为提供程序、树流和流控制器。

在进行外部调用(例如数据库、HTTP 等)时,使用context.Background()context.ToDo()设置截止时间或超时非常重要。如果没有设置,当用户过多且外部服务没有及时响应时,可能会导致您的应用程序出现瓶颈。

我通常会编写一个上下文池的实用函数,其中包括 3 个函数来创建或包装具有超时的新上下文:快速(0.5 秒)、中等(3 秒)、慢速(10 秒)。这样,我就不必一直依赖context.Background(),并且可以轻松地为每个调用设置适当的超时时间。

?
1
2
3
4
5
6
7
8
9
10
const FastTimeout = 500 * time.Millisecond
func WrapCustomContext(ctx context.Context, dur time.Duration) (context.Context, context.CancelFunc) {
    return context.WithTimeout(context.Background(), dur)
}
func GenFastContext() (context.Context, context.CancelFunc) {
    return WrapCustomContext(context.Background(), FastTimeout)
}
func WrapFastContext(ctx context.Context) (context.Context, context.CancelFunc) {
    return WrapCustomContext(ctx, FastTimeout)
}

以上就是从错误中学习改正Go语言五个坏习惯提高编程技巧的详细内容,更多关于Go语言五个编程习惯的资料请关注服务器之家其它相关文章!

原文链接:https://mp.weixin.qq.com/s/Uy7EpGOTo4UaBIatJWByIg

延伸 · 阅读

精彩推荐
  • Golanggolang中对"引用传递"的误解

    golang中对"引用传递"的误解

    这篇文章主要介绍了golang中对“引用传递”的误解,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...

    kumfo4512021-08-10
  • GolangGo语言字典(map)用法实例分析【创建,填充,遍历,查找,修改,删除】

    Go语言字典(map)用法实例分析【创建,填充,遍历,查找,修改,删除】

    这篇文章主要介绍了Go语言字典(map)用法,结合实例形式较为详细的分析了Go语言字典的创建、填充、遍历、查找、修改、删除等操作相关实现技巧,需要的朋...

    52PHP4932020-05-05
  • Golanggolang服务报错: write: broken pipe的解决方案

    golang服务报错: write: broken pipe的解决方案

    在开发在线客服系统的时候,看到日志里有一些错误信息,下面这篇文章主要给大家介绍了关于golang服务报错: write: broken pipe的解决方案,需要的朋友可以参考...

    杰哥的技术杂货铺6682022-09-08
  • Golanggo语言中的json与map相互转换实现

    go语言中的json与map相互转换实现

    本文主要介绍了go语言中的json与map相互转换实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    焱齿9772022-08-16
  • GolangGoFrame通用类型变量gvar与interface基本使用对比

    GoFrame通用类型变量gvar与interface基本使用对比

    这篇文章主要为大家介绍了GoFrame通用类型变量gvar与interface基本使用对比,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职...

    王中阳Go7812022-10-17
  • Golanggo高并发时append方法偶现错误解决分析

    go高并发时append方法偶现错误解决分析

    这篇文章主要为大家介绍了go高并发时append方法偶现错误解决分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    gokingliu5522022-12-01
  • GolangGolang实现AES对称加密的过程详解

    Golang实现AES对称加密的过程详解

    AES是一个对称密码,旨在取代DES成为广泛使用的标准,本文给大家分享Golang实现AES对称加密的过程,本文附有Golang实现AES加密ECB模式的源码,感兴趣的朋友...

    写Golang的小张9062021-06-27
  • Golanggolang 开启opencv图形化编程

    golang 开启opencv图形化编程

    这篇文章主要为大家介绍了golang 开启opencv图形化编程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    灵魂艺术家9262022-11-28