主函数退出方式(Exit)
发布者:admin 发表于:439天前 阅读数:577 评论:0

Go程序使用os.Exit 或者 log.Fatal* 立即退出 (使用panic不是退出程序的好方法,请 don’t panic.)

仅在main()中调用其中一个 os.Exit 或者 **log.Fatal***。所有其他函数应将错误返回到信号失败中。

Bad Good

func main() { body := readFile(path) fmt.Println(body) } func readFile(path string) string { f, err := os.Open(path) if err != nil { log.Fatal(err) } b, err := ioutil.ReadAll(f) if err != nil { log.Fatal(err) } return string(b) } |

func main() { body, err := readFile(path) if err != nil { log.Fatal(err) } fmt.Println(body) } func readFile(path string) (string, error) { f, err := os.Open(path) if err != nil { return "", err } b, err := ioutil.ReadAll(f) if err != nil { return "", err } return string(b), nil } |

原则上:退出的具有多种功能的程序存在一些问题:

不明显的控制流:任何函数都可以退出程序,因此很难对控制流进行推理。

难以测试:退出程序的函数也将退出调用它的测试。这使得函数很难测试,并引入了跳过 go test 尚未运行的其他测试的风险。

跳过清理:当函数退出程序时,会跳过已经进入defer队列里的函数调用。这增加了跳过重要清理任务的风险。

一次性退出

如果可能的话,你的main()函数中最多一次 调用 os.Exit或者log.Fatal。如果有多个错误场景停止程序执行,请将该逻辑放在单独的函数下并从中返回错误。

这会缩短 main()函数,并将所有关键业务逻辑放入一个单独的、可测试的函数中。

Bad Good

package main func main() { args := os.Args[1:] if len(args) != 1 { log.Fatal("missing file") } name := args[0] f, err := os.Open(name) if err != nil { log.Fatal(err) } defer f.Close() // 如果我们调用log.Fatal 在这条线之后 // f.Close 将会被执行. b, err := ioutil.ReadAll(f) if err != nil { log.Fatal(err) } // ... } |

package main func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { args := os.Args[1:] if len(args) != 1 { return errors.New("missing file") } name := args[0] f, err := os.Open(name) if err != nil { return err } defer f.Close() b, err := ioutil.ReadAll(f) if err != nil { return err } // ... } |