各位游戏大佬大家好,今天小编为大家分享关于GG修改器为什么游戏崩溃了_gg修改器修改游戏为什么会游戏崩溃的内容,轻松修改游戏数据,赶快来一起来看看吧。
Golang中defer,panic,recover是很常用的三个特性,三者一起使用可以充当其他语言中try…catch…的角色,而defer本身又像其他语言的析构函数。
defer后边会接一个函数,但该函数不会立刻被执行,而是等到包含它的程序返回时(包含它的函数执行了return语句、运行到函数结尾自动返回、对应的goroutine panic)defer函数才会被执行。通常用于资源释放、打印日志、异常捕获等。
func main() {
f, err := os.Open(filename)
if err != nil {
return err
}
/**
* 这里defer要写在err判断的后边而不是os.Open后边
* 如果资源没有获取成功,就没有必要对资源执行释放操作
* 如果err不为nil而执行资源执行释放操作,有可能导致panic
*/
defer f.Close()
}
如果有多个defer函数,调用顺序类似于栈,越后面的defer函数越先被执行(后进先出)。
func main() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
defer fmt.Println(4)
}
结果:
4
3
2
1
如果包含defer函数的外层函数有返回值,而defer函数中可能会修改该返回值,最终导致外层函数实际的返回值可能与你想象的不一致,这里很容易踩坑,来几个例子:
例1:
func f() (result int) {
defer func() {
result++
}()
return 0
}
例2:
func f() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}
例3:
func f() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}
请先不要向下看,在心里跑一遍上边三个例子的结果,然后去验证 可能你会认为:例1的结果是0,例2的结果是10,例3的结果是6,那么很遗憾地告诉你,这三个结果都错了 为什么呢?最重要的一点就是要明白,return xxx这一条语句并不是一条原子指令 含有defer函数的外层函数,返回的过程是这样的:先给返回值赋值,然后调用defer函数,最后才是返回到更上一级调用函数中,可以用一个简单的转换规则将return xxx改写成:
返回值 = xxx
调用defer函数(这里可能会有修改返回值的操作)
return 返回值
例1,可以改写成这样:
func f() (result int) {
result = 0
//在return之前,执行defer函数
func() {
result++
}()
return
}
所以例1的返回值是1。
例2,可以改写成这样:
func f() (r int) {
t := 5
//赋值
r = t
//在return之前,执行defer函数,defer函数没有对返回值r进行修改,只是修改了变量t
func() {
t = t + 5
}
return
}
所以例2的结果是5。
例3,可以改写成这样:
func f() (r int) {
//给返回值赋值
r = 1
/**
* 这里修改的r是函数形参的值,是外部传进来的
* func(r int){}里边r的作用域只该func内,修改该值不会改变func外的r值
*/
func(r int) {
r = r + 5
}(r)
return
}
所以例3的结果是1。
defer函数的参数值,是在申明defer时确定下来的
在defer函数申明时,对外部变量的引用是有两种方式:作为函数参数和作为闭包引用 作为函数参数,在defer申明时就把值传递给defer,并将值缓存起来,调用defer的时候使用缓存的值进行计算(如上边的例3) 而作为闭包引用,在defer函数执行时根据整个上下文确定当前的值 看个例子:
func main() {
i := 0
defer fmt.Println("a:", i)
//闭包调用,将外部i传到闭包中进行计算,不会改变i的值,如上边的例3
defer func(i int) {
fmt.Println("b:", i)
}(i)
//闭包调用,捕获同作用域下的i进行计算
defer func() {
fmt.Println("c:", i)
}()
i++
}
结果:
c: 1
b: 0
a: 0
func panic(v interface{})
中英文说明 :
The panic built-in function stops normal execution of the current goroutine.When a function F calls panic, normal execution of F stops immediately.Any functions whose execution was deferred by F are run in the usual way, and then F returns to its caller. To the caller G, the invocation of F then behaves like a call to panic,terminating G’s execution and running any deferred functions.This continues until all functions in the executing goroutine have stopped,in reverse order. At that point, the program is terminated and the error condition is reported,including the value of the argument to panic. This termination sequence is called panicking and can be controlled by the built-in function recover.
panic内置函数停止当前goroutine的正常执行,当函数F调用panic时,函数F的正常执行被立即停止,然后运行所有在F函数中的defer函数,然后F返回到调用它的函数对于调用者G,F函数的行为就像panic一样,终止G的执行并运行G中所defer函数,此过程会一直继续执行到goroutine所有的函数。panic可以通过内置的recover来捕获。
func recover() interface{}
中英文说明
The recover built-in function allows a program to manage behavior of a panicking goroutine. Executing a call to recover inside a deferred function (but not any function called by it) stops the panicking sequence by restoring normal execution and retrieves the error value passed to the call of panic. If recover is called outside the deferred function it will not stop a panicking sequence. In this case, or when the goroutine is not panicking, or if the argument supplied to panic was nil, recover returns nil. Thus the return value from recover reports whether the goroutine is panicking.
recover内置函数用来管理含有panic行为的goroutine,recover运行在defer函数中,获取panic抛出的错误值,并将程序恢复成正常执行的状态。如果在defer函数之外调用recover,那么recover不会停止并且捕获panic错误如果goroutine中没有panic或者捕获的panic的值为nil,recover的返回值也是nil。由此可见,recover的返回值表示当前goroutine是否有panic行为
这里有几个需要注意的问题,通过例子表现:
1、defer 表达式的函数如果定义在 panic 后面,该函数在 panic 后就无法被执行到。
在defer前panic
func main() {
panic("a")
defer func() {
fmt.Println("b")
}()
}
结果,b没有被打印出来:
panic: a
goroutine 1 [running]:
main.main()
/xxxxx/src/xxx.go:50 +0x39
exit status 2
而在defer后panic
func main() {
defer func() {
fmt.Println("b")
}()
panic("a")
}
结果,b被正常打印:
b
panic: a
goroutine 1 [running]:
main.main()
/xxxxx/src/xxx.go:50 +0x39
exit status 2
2、F中出现panic时,F函数会立刻终止,不会执行F函数内panic后面的内容,但不会立刻return,而是调用F的defer,如果F的defer中有recover捕获,则F在执行完defer后正常返回,调用函数F的函数G继续正常执行。
func G() {
defer func() {
fmt.Println("c")
}()
F()
fmt.Println("继续执行")
}
func F() {
defer func() {
if err := recover(); err != nil {
fmt.Println("捕获异常:", err)
}
fmt.Println("b")
}()
panic("a")
}
结果:
捕获异常: a
b
继续执行
c
3、如果F的defer中无recover捕获,则将panic抛到G中,G函数会立刻终止,不会执行G函数内后面的内容,但不会立刻return,而调用G的defer…以此类推。
func G() {
defer func() {
if err := recover(); err != nil {
fmt.Println("捕获异常:", err)
}
fmt.Println("c")
}()
F()
fmt.Println("继续执行")
}
func F() {
defer func() {
fmt.Println("b")
}()
panic("a")
}
结果:
b
捕获异常: a
c
4、如果一直没有recover,抛出的panic到当前goroutine最上层函数时,程序直接异常终止。
func G() {
defer func() {
fmt.Println("c")
}()
F()
fmt.Println("继续执行")
}
func F() {
defer func() {
fmt.Println("b")
}()
panic("a")
}
结果:
b
c
panic: a
goroutine 1 [running]:
main.F()
/xxxxx/src/xxx.go:61 +0x55
main.G()
/xxxxx/src/xxx.go:53 +0x42
exit status 2
5、recover都是在当前的goroutine里进行捕获的,这就是说,对于创建goroutine的外层函数,如果goroutine内部发生panic并且内部没有用recover,外层函数是无法用recover来捕获的,这样会造成程序崩溃。
func G() {
defer func() {
//goroutine外进行recover
if err := recover(); err != nil {
fmt.Println("捕获异常:", err)
}
fmt.Println("c")
}()
//创建goroutine调用F函数
go F()
time.Sleep(time.Second)
}
func F() {
defer func() {
fmt.Println("b")
}()
//goroutine内部抛出panic
panic("a")
}
结果:
b
panic: a
goroutine 5 [running]:
main.F()
/xxxxx/src/xxx.go:67 +0x55
created by main.main
/xxxxx/src/xxx.go:58 +0x51
exit status 2
6、recover返回的是interface{}类型而不是go中的 error 类型,如果外层函数需要调用err.Error(),会编译错误,也可能会在执行时panic。
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("捕获异常:", err.Error())
}
}()
panic("a")
}
编译错误,结果:
err.Error undefined (type interface {} is interface with no methods)
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("捕获异常:", fmt.Errorf("%v", err).Error())
}
}()
panic("a")
}
结果:
捕获异常: a
以上就是关于GG修改器为什么游戏崩溃了_gg修改器修改游戏为什么会游戏崩溃的全部内容,游戏大佬们学会了吗?
免root是用GG修改器,免root神器GG修改器 分类:免root版 5,287人在玩 在Android手机中使用一些应用程序需要root权限,而root是一个比较麻烦的过程,很多人不会或不敢进行。但是如今有了GG修改器这个神器,再也不需要担心root问题了! 什么是GG修改器?……
下载gg修改器怎么先root,下载一个好用的gg修改器,先root你的设备 分类:免root版 3,166人在玩 如果你是一位喜欢在手机游戏中获得优势的玩家,那么你一定听说过GG修改器。GG修改器是一款Android平台上的优秀工具,可以帮助用户修改游戏数据,比如金币、钻石、经验等等。但是,……
下载gg有免root修改器_gg免root修改器下载教程 分类:免root版 5,511人在玩 各位游戏大佬大家好,今天小编为大家分享关于gg有免root修改器_gg免root修改器下载教程的内容,轻松修改游戏数据,赶快来一起来看看吧。 本文作者:我不是喷子X LG这个牌子相信各……
下载王者gg修改器无root_王者怎么使用gg修改器 分类:免root版 6,751人在玩 各位游戏大佬大家好,今天小编为大家分享关于王者gg修改器无root_王者怎么使用gg修改器的内容,轻松修改游戏数据,赶快来一起来看看吧。 hi,大家好 我是王者老斯基 关注我,带你……
下载gg修改器兔root版下载,下载gg修改器兔root版,让您的游戏更加畅快! 分类:免root版 4,348人在玩 如果您是一名游戏爱好者,那么您肯定知道GG修改器兔root版。这是一款非常实用的软件,可以帮助您在游戏中获得无限资源、无敌状态等各种优势,从而轻松通关游戏,享受游戏乐趣。今天……
下载gg修改器汉化免root_gg修改器汉化最新版 分类:免root版 6,428人在玩 各位游戏大佬大家好,今天小编为大家分享关于gg修改器汉化免root_gg修改器汉化最新版的内容,轻松修改游戏数据,赶快来一起来看看吧。 据官方介绍,在过去的8个月中,Android Studi……
下载gg修改器兔root版下载_gg修改器官方免root下载 分类:免root版 5,565人在玩 各位游戏大佬大家好,今天小编为大家分享关于gg修改器兔root版下载_gg修改器官方免root下载的内容,轻松修改游戏数据,赶快来一起来看看吧。 小哥嘚嘚 经过小哥好多好多的尝试终于……
下载gg修改器 已root,GG修改器为您的游戏体验打造完美辅助 分类:免root版 3,931人在玩 随着游戏技术的不断发展,越来越多的玩家开始尝试使用各种辅助工具,以提高游戏体验和获得更优秀的成绩。而其中最常用的辅助工具之一便是GG修改器。这款软件能够帮助您轻松修改游戏……
下载gg修改器怎么同意root_gg修改器怎么使 分类:免root版 4,954人在玩 各位游戏大佬大家好,今天小编为大家分享关于gg修改器怎么同意root_gg修改器怎么使的内容,轻松修改游戏数据,赶快来一起来看看吧。 写在前面 笔记是上课后整理的笔记,适合温习……
下载gg修改器免root板,免root修改器GG让你享受无限乐趣的终极工具 分类:免root版 4,790人在玩 如果你是一位游戏爱好者,那么你一定知道修改器的作用。通过使用修改器,你可以轻松地修改游戏内的属性、角色等内容,从而获得更多的游戏乐趣和体验。但是,大多数修改器需要Root权……
下载