「兔了个兔」模拟兔子的一天:浅聊Go关键字defer

1,526 阅读3分钟

我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛

模拟兔子的一天:浅聊Go关键字defer

作者:千石
本文专栏:兔了个兔
支持作者:点赞、评论、收藏

一则小故事

(故事的代码实现见文末码上掘金)

有一只可爱的兔子,它生活在一个充满生机和活力的小村庄。兔子非常喜欢新春,每年都会热烈庆祝。然而,有一年,兔子在新春庆祝活动后忘记了关闭灯光,电费比平时贵很多。

兔子想通过程序来控制灯光的关闭,以防止自己忘记关灯,于是它决定学习一门编程语言,希望能找到一种解决问题的方法。它选择了 Go 语言,并快速学会了如何使用 Go 语言的 defer 关键字。

兔子通过使用 defer 关键字,很容易地解决了上述问题。在新春庆祝活动中,兔子在关闭灯光前,通过使用 defer 关键字将关闭灯光的代码推迟到了庆祝活动结束之后执行。

从此以后,兔子再也不用担心忘记关闭灯光的问题了!

正文

通过上面的这则小故事,我们可以看出,defer 关键字允许程序员将一个函数的执行推迟到函数结束时执行。接下来,让我们聊聊Go语言的defer关键字。

介绍defer

"defer" 是 Go 语言的一个关键字,它可以在函数结束前延迟执行一个语句。使用方法是在要延迟执行的语句前面加上 "defer",具体语法如下:

defer <expression>

它通常用于释放资源(如打开的文件),在程序结束前执行清理工作,或者在特定的代码块中执行必要的操作。"defer" 的执行顺序类似于栈的顺序,即后进先出(LIFO),最后被压入栈的语句会最先执行。

image.png

优点:

  1. 简化代码:defer关键字允许我们将重要的清理操作放在一个地方,从而使代码更简洁。
  2. 防止资源泄露:使用defer语句可以确保在函数结束时释放资源,避免内存泄漏等问题。
  3. 简化错误处理:defer关键字可以简化错误处理,在函数结束前执行清理操作,避免出现不必要的错误。
  4. 提高代码可读性:defer关键字可以使代码更具可读性,因为它把重要的操作统一放在一起,易于理解。

一些细节

参数

"defer" 语句的参数在被延迟执行时被计算,而不是在 "defer" 语句执行时。因此,如果参数是一个函数调用,它会在被延迟执行时立即调用。

package main

import "fmt"

func main() {
    i := 1
    defer fmt.Println("defer value:", func() int { return i * 2 }())
    i++
    fmt.Println("main value:", i)
    // Output:
    // main value: 2
    // defer value: 2
}

参数作用域

"defer" 语句的参数在函数内可见,因此如果 "defer" 语句引用了外部变量,则变量的值将在 "defer" 语句被延迟执行时被计算。

package main

import "fmt"

func main() {
    i := 1
    defer fmt.Println("defer value:", i)
    i++
    fmt.Println("main value:", i)
    // Output:
    // main value: 2
    // defer value: 1
}

在函数中的执行顺序

"defer" 语句在函数中按照后进先出(LIFO)的顺序执行,即最后被压入栈的语句最先执行。

package main

import "fmt"

func main() {
    defer fmt.Println("defer 1")
    defer fmt.Println("defer 2")
    defer fmt.Println("defer 3")
    fmt.Println("main")
    // Output:
    // main
    // defer 3
    // defer 2
    // defer 1
}

在控制结构中的执行顺序

如果一个函数内包含多个控制结构(如循环),则 "defer" 语句在每个控制结构中都有自己的执行顺序,并且受该结构的范围限制。

package main

import "fmt"

func main() {
    for i := 0; i < 3; i++ {
        defer fmt.Println("defer in loop", i)
    }
    fmt.Println("main")
    // Output:
    // main
    // defer in loop 2
    // defer in loop 1
    // defer in loop 0
}

一些🌰

  1. 资源释放:
func ReadFile(filename string) {
    file, err := os.Open(filename)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer file.Close()

    // 读取文件
    // ...
}

在这个例子中,我们使用defer语句确保文件在函数结束时被关闭。

  1. 延迟初始化:
func init() {
    // 延迟初始化
    defer fmt.Println("Init complete.")
}

在这个例子中,我们使用defer语句实现延迟初始化。

  1. 错误处理:
func handleError(err error) {
    defer fmt.Println("Error handled.")
    if err != nil {
        // 处理错误
        // ...
    }
}

在这个例子中,我们使用defer语句确保错误被处理并且消息被打印。

最后

总结

本文详细介绍了Go语言的defer关键字,包括它的定义、语法、作用以及实际应用。defer关键字是Go语言中一种非常有用的特性,它可以简化代码,防止资源泄露,简化错误处理,提高代码可读性。

创作不易,如果你觉得本文对你有帮助,可以点赞、评论、收藏,你的支持是我最大的动力,下次更新会更快!

b54ac82fc1b4dec830e3995ee3ad92e.jpg c9895d976d1772e420c80b8171e6eb1.jpg fe6de72313429bb4c4b2449c7e16ebc.jpg

最后,祝大家兔年快乐!

码上掘金