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()
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
}
}
|
最后编辑: kuteng 文档更新时间: 2021-05-09 20:12 作者:kuteng