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

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

引言

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

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

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

让我们深入探讨。

1. 使用 init()

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

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

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

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

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

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

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

2. 使用全局变量

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

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

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

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

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

3. 忽略错误消息

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

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

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

// 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”可以捕捉到恐慌,允许更加控制地处理意外情况。

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

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()函数之后立即放置关闭函数。

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(),并且可以轻松地为每个调用设置适当的超时时间。

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语言编程习惯的资料请关注脚本之家其它相关文章!

相关文章

  • 一文让你理解go语言的Context

    一文让你理解go语言的Context

    在Go语言中,Context(上下文)是一个类型,用于在程序中传递请求范围的值、截止时间、取消信号和其他与请求相关的上下文信息,它在多个goroutine之间传递这些值,使得并发编程更加可靠和简单,本文详细介绍go语言的Context,需要的朋友可以参考下
    2023-05-05
  • golang并发ping主机的方法

    golang并发ping主机的方法

    今天小编就为大家分享一篇golang并发ping主机的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • 超越传统:Go语言并发编程的新境界

    超越传统:Go语言并发编程的新境界

    Go语言是一种开源的编程语言,以其强大的并发编程能力而闻名,本文将介绍Go语言并发编程的新境界,探讨如何利用Go语言的特性来实现高效的并发编程,需要的朋友可以参考下
    2023-10-10
  • golang 用msgpack高效序列化的案例

    golang 用msgpack高效序列化的案例

    msgpack是一个非常受欢迎的Go序列化库,具有很好的跨语言支持,这篇文章主要介绍了golang 用msgpack高效序列化的相关知识,需要的朋友可以参考下
    2023-05-05
  • go语言打包的网页wasm示例详解

    go语言打包的网页wasm示例详解

    这篇文章主要为大家介绍了go打包网页wasm示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2022-09-09
  • Go语言设计实现在任务栏里提醒你喝水的兔子

    Go语言设计实现在任务栏里提醒你喝水的兔子

    这篇文章主要为大家介绍了Go语言设计实现在任务栏里提醒你喝水的兔子示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • Golang桥接模式讲解和代码示例

    Golang桥接模式讲解和代码示例

    桥接是一种结构型设计模式,可将业务逻辑或一个大类拆分为不同的层次结构,从而能独立地进行开发,本文将通过代码示例详细给大家介绍一下Golang桥接模式,需要的朋友可以参考下
    2023-06-06
  • Go语言实现汉诺塔算法

    Go语言实现汉诺塔算法

    之前的文章,我们给大家分享了不少汉诺塔算法的实现语言,包括C、c++、java、python等,今天我们就来使用go语言来实现一下,需要的小伙伴来参考下吧。
    2015-03-03
  • Go语言自带测试库testing使用教程

    Go语言自带测试库testing使用教程

    这篇文章主要为大家介绍了Go语言自带测试库testing使用教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • Go语言并发编程之互斥锁Mutex和读写锁RWMutex

    Go语言并发编程之互斥锁Mutex和读写锁RWMutex

    Go 语言中提供了很多同步工具,本文将介绍互斥锁Mutex和读写锁RWMutex的使用方法,想要具体了解的小伙伴,请参考下面文章详细内容,希望对你有所帮助
    2021-10-10

最新评论