📅  最后修改于: 2023-12-03 14:41:37.161000             🧑  作者: Mango
在GO语言中,defer语句用于在函数返回前执行一些必要的清理工作。这个特性有点类似Java或C#中的finally语句。本文将详细介绍GO语言中的defer特性,其语法和使用场景。
defer语句的语法很简单:在需要执行的语句前加上关键字defer,可以看做是一个栈,最后执行的defer语句最先被执行。如下是一个简单的例子:
package main
import "fmt"
func main() {
defer fmt.Println("deferred")
fmt.Println("not deferred")
}
输出结果如下:
not deferred
deferred
可以看到,如果某个函数中涉及到多个defer语句,它们会按栈的特性依次执行。
defer语句需要注意,延迟函数的参数在defer语句被调用时被执行,并不是在被调用函数的执行中被执行。如下是一个例子:
func test() {
i := 1
defer fmt.Println(i)
i++
}
该函数输出结果为1
,而不是2
。这是因为i在defer语句被执行的时候被求值。
defer一个函数最常用的场景是处理共享的资源,如文件、数据库连接、套接字和格式化输出等。当然,难免有些程序员都用了defer所代表的的作用(清理资源)却没有真正的清理掉它们。
package main
import "fmt"
func readwrite() {
f, _ := os.Create("test.txt")
defer f.Close()
fmt.Fprintln(f, "Hello, world!")
f.Read(...)
}
f.Close()这个语句会在这个函数结束前被执行。这种模式可以应用于在函数进入时初始化一个资源,然后在函数返回或发生异常时,通过defer语句释放该资源。这种模式可以避免因忘记释放资源而导致的问题。
defer语句在函数返回或panic时被执行,这也是一种处理错误或异常的机制。如果函数中已有其他执行返回或发生错误的路径,那么在这个路径的末尾增加一个defer语句也会让代码变得更加容易维护。下面是一个例子:
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
如果从srcName打开文件失败,CopyFile函数会直接返回并跳过后面的两个defer。如果在创建dstName文件时失败,则只会执行第一个defer语句,并关闭了src文件。如果拷贝操作发生错误并返回,那么两个文件都会安全地关闭。
defer是GO语言中一个很好的特性,可以使得代码变得简洁并避免一些类似资源处理的错误。在本文中,我们介绍了defer的语法和用法,并给出了一些使用场景供读者参考。