第13节 Go语言退出、结束函数或者协程方式

❤️💕💕Go语言高级篇章,在此之前建议您先了解基础和进阶篇。Myblog:http://nsddd.topopen in new window

Go语言基础篇open in new window

Go语言100篇进阶open in new window


[TOC]

提示

Go语言中有很多让我觉得误解的一些终结语句,我想 blockcontinue 只是最基本的也是最简单的。

Go语言几种退出程序的方式:

  1. os.Exit() 退出程序
  2. panic() 抛出异常
  3. return 退出函数
  4. defer + recover() 捕获异常
  5. runtime.Goexit() 退出当前协程
  6. os.Kill 杀死进程
  7. os.Interrupt 中断进程
  8. block 跳出循环 (不讲)
  9. continue 跳出当前循环 继续下一次循环 (不讲)

runtime.Goexit() 退出当前协程

💡简单的一个案例如下:

package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	//Go语言几种退出程序的方式
	//1. os.Exit() 退出程序
	//2. panic() 抛出异常
	//3. return 退出函数
	//4. defer + recover() 捕获异常
	//5. runtime.Goexit() 退出当前协程
	//6. os.Kill 杀死进程
	//7. os.Interrupt 中断进程
	//8. block 跳出循环
	//9. continue  跳出当前循环 继续下一次循环

	fmt.Println("main() 开始的部分")
	go func() {
		fmt.Println("go func() 开始的部分")
		func() {
			fmt.Println("func() 开始的部分")
			go func() {
				fmt.Println("最里面go func() 开始的部分")
				runtime.Goexit() //退出当前协程

				fmt.Println("最里面go func() 结束的部分")
			}()
			fmt.Println("func() 结束的部分")
            //等待2s
			time.Sleep(2 * time.Second)
		}()
		fmt.Println("go func() 结束的部分")
	}()
	//等待5s
	time.Sleep(time.Second * 5)
	fmt.Println("main() 结束的部分")
}

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\61-main.go"
main() 开始的部分
go func() 开始的部分
func() 开始的部分
最里面go func() 开始的部分
func() 结束的部分
go func() 结束的部分
main() 结束的部分

📜 对上面的解释:

runtime.Goexit() //退出当前协程

只是退出当前的 go func() 协程,并不是当前函数。

os.Exit(-1) 退出当前程序

函数定义:

函数定义:func Exit(code int)

Exit 函数可以让当前程序以给出的状态码 code 退出。一般来说,状态码 0 表示成功,非 0 表示出错。程序会立刻终止,并且 defer 的函数不会被执行。

package main

import (
	"fmt"
	"os"
)

func main() {
	var num int = 0

	fmt.Printf("Enter number:")
	fmt.Scanf("%d", &num)

	if num > 0 {
		fmt.Printf("n > 0  Program terminated\n")
		os.Exit(0)
	} else if num < 0 {
		fmt.Printf("n < 0  Program continue\n")
	}
	fmt.Printf("Program finished normally\n")
}

🚀 编译结果如下:

PS D:\文档\最近的\awesome-golang\docs\code\go-super> go run .\66-main.go
Enter number:2
n > 0  Program terminated
PS D:\文档\最近的\awesome-golang\docs\code\go-super> go run .\66-main.go
Enter number:-1
n < 0  Program continue
Program finished normally
PS D:\文档\最近的\awesome-golang\docs\code\go-super> go run .\66-main.go
Enter number:0
Program finished normally

💡简单的一个案例如下:

package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	fmt.Println("main() 开始的部分")
	go func() {
		fmt.Println("go func() 开始的部分")
		func() {
			fmt.Println("func() 开始的部分")
			go func() {
				fmt.Println("最里面go func() 开始的部分")
				os.Exit(-1) //退出程序

				fmt.Println("最里面go func() 结束的部分")
			}()
			//等待2s
			time.Sleep(2 * time.Second)    
			fmt.Println("func() 结束的部分")
		}()
		fmt.Println("go func() 结束的部分")
	}()
	//等待5s
	time.Sleep(time.Second * 5)
	fmt.Println("main() 结束的部分")
}

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\61-main.go"
main() 开始的部分
go func() 开始的部分
func() 开始的部分
最里面go func() 开始的部分
exit status 0xffffffff

📜 对上面的解释:

os.Exit(-1) //退出程序

退出当前的 func main() 程序

os.Exit(0) 中断进程

💡简单的一个案例如下:

package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	fmt.Println("main() 开始的部分")
	go func() {
		fmt.Println("go func() 开始的部分")
		func() {
			fmt.Println("func() 开始的部分")
			go func() {
				fmt.Println("最里面go func() 开始的部分")
				//中断进程
				os.Exit(0)

				fmt.Println("最里面go func() 结束的部分")
			}()
			//等待2s
			time.Sleep(2 * time.Second)
			fmt.Println("func() 结束的部分")

		}()
		fmt.Println("go func() 结束的部分")
	}()
	//等待5s
	time.Sleep(time.Second * 5)
	fmt.Println("main() 结束的部分")
}

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\63-main.go"
main() 开始的部分
go func() 开始的部分
func() 开始的部分
最里面go func() 开始的部分

📜 对上面的解释:

状态码为 0 ,退出但是不报错

panic() 抛出异常退出

或许你可以使用defer func() 抛出异常继续执行
package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("main() 开始的部分")
	go func() {
		fmt.Println("go func() 开始的部分")
		func() {
			fmt.Println("func() 开始的部分")
			go func() {
				fmt.Println("最里面go func() 开始的部分")
				//defer异常捕获
				defer func() {
					if err := recover(); err != nil {
						fmt.Println("最里面go func() defer异常捕获", err)
					}
				}()
				panic("最里面go func() 抛出异常退出")
				fmt.Println("最里面go func() 结束的部分")
			}()
			//等待2s
			time.Sleep(2 * time.Second)
			fmt.Println("func() 结束的部分")
		}()
		fmt.Println("go func() 结束的部分")
	}()
	//等待5s
	time.Sleep(time.Second * 5)
	fmt.Println("main() 结束的部分")
}

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\61-main.go"
main() 开始的部分
go func() 开始的部分
func() 开始的部分
最里面go func() 开始的部分
最里面go func() defer异常捕获 最里面go func() 抛出异常退出
func() 结束的部分
go func() 结束的部分
main() 结束的部分

💡简单的一个案例如下:

package main

import (
	"fmt"
	"time"
)

func main() {
	//Go语言几种退出程序的方式
	//1. os.Exit() 退出程序
	//2. panic() 抛出异常
	//3. return 退出函数
	//4. defer + recover() 捕获异常
	//5. runtime.Goexit() 退出当前协程
	//6. os.Kill 杀死进程
	//7. os.Interrupt 中断进程
	//8. block 跳出循环
	//9. continue  跳出当前循环 继续下一次循环

	fmt.Println("main() 开始的部分")
	go func() {
		fmt.Println("go func() 开始的部分")
		func() {
			fmt.Println("func() 开始的部分")
			go func() {
				fmt.Println("最里面go func() 开始的部分")

				panic("最里面go func() 抛出异常退出")
				fmt.Println("最里面go func() 结束的部分")
			}()
			//等待2s
			time.Sleep(2 * time.Second)
            fmt.Println("func() 结束的部分")
		}()
		fmt.Println("go func() 结束的部分")
	}()
	//等待5s
	time.Sleep(time.Second * 5)
	fmt.Println("main() 结束的部分")
}

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\61-main.go"
main() 开始的部分
go func() 开始的部分
func() 开始的部分
最里面go func() 开始的部分
panic: 最里面go func() 抛出异常退出

goroutine 7 [running]:
main.main.func1.1.1()
	d:/文档/最近的/awesome-golang/docs/code/go-super/61-main.go:28 +0x65
created by main.main.func1.1
	d:/文档/最近的/awesome-golang/docs/code/go-super/61-main.go:25 +0x65
exit status 2

📜 对上面的解释:

可以看出来这两者之间的差距,recover()使得 程序结束当前协程~继续执行使用。

不使用的化,会直接退出~

return 跳出当前函数

return 是我们最常用的一个用法:在设定返回值为1002,然后return触发defer语句,执行完成后(即便是defer抛出panic后被捕获),返回1002。

我们都知道 panic 会触发defer 由于 return会触发 defer,函数抛出 panic 也会触发 defer。所以我们可以在 defer 中,特别是通过 recovery() 函数捕获 panic 后,修改函数的返回值。

func main() {
	fmt.Println(Test0())
}
 
func Test0()(ret string){
	defer func() {
		err:=recover()
		if err!=nil{
			ret=fmt.Sprint(err)
		}
	}()
	panic("this is a panic")
	return "normal"
}

🚀 编译结果如下:

this is a panic

📜 对上面的解释:

注意 panicreturn 的循序很重要,如果当 return "normal" 在前面,那么很明显会输出 normalthis is a panic 将不会输出。

💡简单的一个案例如下:

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println("main() 开始的部分")
	go func() {
		fmt.Println("go func() 开始的部分")
		func() {
			fmt.Println("func() 开始的部分")
			go func() {
				fmt.Println("最里面go func() 开始的部分")
				return

				fmt.Println("最里面go func() 结束的部分")
			}()
			//等待2s
			time.Sleep(2 * time.Second)
			fmt.Println("func() 结束的部分")
		}()
		fmt.Println("go func() 结束的部分")
	}()
	//等待5s
	time.Sleep(time.Second * 5)
	fmt.Println("main() 结束的部分")
}

🚀 编译结果如下:

[Running] go run "d:\文档\最近的\awesome-golang\docs\code\go-super\61-main.go"
main() 开始的部分
go func() 开始的部分
func() 开始的部分
最里面go func() 开始的部分
func() 结束的部分
go func() 结束的部分
main() 结束的部分

::: warning📜 对上面的解释: return 直接跳出当前的函数, 注意这个函数也可以是当前的协程 go func()

:::

Lable跳转标签

💡简单的一个案例如下:

package main

import (
	"fmt"
	"time"
)

func main() {
	//Go语言几种退出程序的方式
	//1. os.Exit() 退出程序
	//2. panic() 抛出异常
	//3. return 退出函数
	//4. defer + recover() 捕获异常
	//5. runtime.Goexit() 退出当前协程
	//6. os.Kill 杀死进程
	//7. os.Interrupt 中断进程
	//8. block 跳出循环
	//9. continue  跳出当前循环 继续下一次循环

	fmt.Println("main() 开始的部分")
	go func() {
		fmt.Println("go func() 开始的部分")
		func() {

			fmt.Println("func() 开始的部分")
			go func() {
			Lable1:
				fmt.Println("最里面go func() 开始的部分")
				//等待1s
				time.Sleep(time.Second)
				// 标签跳转
				goto Lable1

				fmt.Println("最里面go func() 结束的部分")
			}()
			//等待2s
			time.Sleep(2 * time.Second)
			fmt.Println("func() 结束的部分")

		}()
		fmt.Println("go func() 结束的部分")
	}()
	//等待5s
	time.Sleep(time.Second * 5)
	fmt.Println("main() 结束的部分")
}

🚀 编译结果如下:

PS D:\文档\最近的\awesome-golang\docs\code\go-super> go run .\64-main.go
main() 开始的部分
go func() 开始的部分
func() 开始的部分
最里面go func() 开始的部分
最里面go func() 开始的部分
func() 结束的部分
go func() 结束的部分
最里面go func() 开始的部分
最里面go func() 开始的部分
最里面go func() 开始的部分
main() 结束的部分

END 链接