Go defer语句&作用域

1 defer 语句

defer是Go语言提供的关键字,用于资源的释放,会在函数返回之前进行调用。

defer语句是Go中一个非常有用的特性,可以将一个方法延迟到包裹该方法的方法返回时执行,在实际应用中,defer语句可以充当其他语言中try…catch…的角色,也可以用来处理关闭文件句柄等收尾操作。

1.1 defer 执行

func main() {
	//defer 语句
	deferDemo()
}

func deferDemo() {
	fmt.Println("start")
	defer fmt.Println("hello")
	defer fmt.Println("world")
	fmt.Println("end")
}

输出结果:

start
end
world
hello

当一个方法中有多个defer时, defer会将要延迟执行的方法“压栈”,当defer被触发时,将所有“压栈”的方法“出栈”并执行。所以defer的执行顺序是LIFO

1.1.1 defer的面试题

考虑下面代码的输出

func main() {
	defer func() {
		fmt.Println("hello")
	}()
	defer func() {
		fmt.Println("world")
	}()
	defer func() {
		fmt.Println("go")
	}()
}

输出结果:

go
world
hello

在for循环中使用defer可能导致的性能问题

func deferInLoops() {
    for i := 0; i < 100; i++ {
        f, _ := os.Open("/etc/hosts")
        defer f.Close()
    }
}

defer在紧邻创建资源的语句后生命力,看上去逻辑没有什么问题。但是和直接调用相比,defer的执行存在着额外的开销,例如defer会对其后需要的参数进行内存拷贝,还需要对defer结构进行压栈出栈操作。所以在循环中定义defer可能导致大量的资源开销,在本例中,可以将f.Close()语句前的defer去掉,来减少大量defer导致的额外资源消耗。

坑: 判断执行没有err之后,再defer释放资源
一些获取资源的操作可能会返回err参数,我们可以选择忽略返回的err参数,但是如果要使用defer进行延迟释放的的话,需要在使用defer之前先判断是否存在err,如果资源没有获取成功,即没有必要也不应该再对资源执行释放操作。如果不判断获取资源是否成功就执行释放操作的话,还有可能导致释放方法执行错误。

2 变量作用域

2.1 全局变量

全局变量是定义在函数外部的变量,它在程序整个运行周期内都有效。

package main

import "fmt"

var x = 100

func main() {
	f1()
}

func f1(){
	fmt.Println(x)
}

2.2 局部变量

函数内定义的变量无法在该函数外使用

func testDemo() {
	//定义一个函数局部变量x,仅在该函数内生效
	var x int64 = 100
	fmt.Printf("x=%d\n", x)
}

func main() {
	testDemo()
	fmt.Println(x) // 此时无法使用变量x
}

如果局部变量和全局变量重名,优先访问局部变量。

package main

import "fmt"

//定义全局变量num
var num int64 = 10

func testNum() {
	num := 100
	fmt.Printf("num=%d\n", num) // 函数中优先使用局部变量
}
func main() {
	testNum() // num=100
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值