从错误中学习改正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语言中实现enum枚举的方法详解

    Go语言中实现enum枚举的方法详解

    枚举,即 enum,可用于表示一组范围固定的值,它能助我们写出清晰、安全的代码,那么你是否了解过 Go 中的枚举呢?下面就跟随小编一起来学习一下Go语言中实现enum枚举的常用方法吧
    2024-02-02
  • Go与C语言的互操作实现

    Go与C语言的互操作实现

    在Go与C语言互操作方面,Go更是提供了强大的支持。尤其是在Go中使用C,你甚至可以直接在Go源文件中编写C代码,本文就详细的介绍一下如何使用,感兴趣的可以了解一下
    2021-12-12
  • Go简单实现协程方法

    Go简单实现协程方法

    本文主要介绍了Go简单实现协程的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-12-12
  • Go语言中的方法定义用法分析

    Go语言中的方法定义用法分析

    这篇文章主要介绍了Go语言中的方法定义用法,实例分析了方法的定义及使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • Golang学习之map的用法详解

    Golang学习之map的用法详解

    在Golang(又称Go语言)中,map是一种非常有用的数据结构,所以这篇文章小编就来带大家一起深入了解一下map的用法,感兴趣的小伙伴可以了解一下
    2023-06-06
  • go语言实现的memcache协议服务的方法

    go语言实现的memcache协议服务的方法

    这篇文章主要介绍了go语言实现的memcache协议服务的方法,实例分析了Go语言使用memcache的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • Golang结合ip2region实现ip归属地查询

    Golang结合ip2region实现ip归属地查询

    ip2region - 是一个离线IP地址定位库和IP定位数据管理框架,提供了众多主流编程语言的 xdb 数据生成和查询客户端实现,下面我们就来看看Golang如何结合ip2region实现ip归属地查询吧
    2024-03-03
  • 详解如何在Go语言中调用C源代码

    详解如何在Go语言中调用C源代码

    这篇文章主要为大家详细介绍了如何在Go语言中调用C语言源代码,文中的示例代码讲解详细,对我们学习或工作有一定的帮助,需要的可以参考一下
    2022-05-05
  • 使用Go语言编写一个极简版的容器Container

    使用Go语言编写一个极简版的容器Container

    Docker作为一种流行的容器化技术,对于每一个程序开发者而言都具有重要性和必要性,因为容器化相关技术的普及大大简化了开发环境配置、更好的隔离性和更高的安全性,对于部署项目和团队协作而言也更加方便,本文将尝试使用Go语言编写一个极简版的容器
    2023-10-10
  • golang RPC包原理和使用详细介绍

    golang RPC包原理和使用详细介绍

    golang的rpc支持三个级别的RPC:TCP、HTTP、JSONRPC。但Go的RPC包是独一无二的RPC,它和传统的RPC系统不同,它只支持Go开发的服务器与客户端之间的交互,因为在内部,它们采用了Gob来编码
    2022-09-09

最新评论