编程语言 18、孰能无过-GOLANG xiu 2023-05-13 2024-11-27 处理错误 go语言支持多个返回值,按照惯例我们把错误放在最后一个返回值返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport ( "fmt" "io/ioutil" "os" ) func main () { files, error := ioutil.ReadDir("." ) if error != nil { fmt.Println(error ) os.Exit(1 ) } for _, value := range files { fmt.Println(value.Name()) } }
尝试读取一个虚构文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport ( "fmt" "io/ioutil" "os" ) func main () { files, error := ioutil.ReadDir("nullfile.txt" ) if error != nil { fmt.Println(error ) os.Exit(1 ) } for _, value := range files { fmt.Println(value.Name()) } }
优雅的处理错误 文件写入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package mainimport ( "fmt" "os" ) func proverbs (name string ) error { f, err := os.Create(name) if err != nil { return err } _, err = fmt.Fprintln(f, "Errors are values." ) if err != nil { f.Close() return err } _, err = fmt.Fprintln(f, "Don`t just check errors,handle them gracefully." ) f.Close() return err } func main () { err := proverbs("1.txt" ) if err != nil { fmt.Println(err) os.Exit(1 ) } }
上面这种错误处理方式看着逻辑很清晰,但是充斥着大量的错误判断的语句,使代码整体结构变得复杂
关键字defer 如果一个函数在内部使用了defer延迟了某些操作,那么go语言将保证这些被延迟的操作会在函数返回之前触发,如下面的例子,出现在关键字之后的每一个return语句都会导致f.Close(),方法被调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package mainimport ( "fmt" "os" ) func proverbs (name string ) error { f, err := os.Create(name) if err != nil { return err } defer f.Close() _, err = fmt.Fprintln(f, "Errors are values." ) if err != nil { return err } _, err = fmt.Fprintln(f, "Don`t just check errors,handle them gracefully." ) return err } func main () { err := proverbs("1.txt" ) if err != nil { fmt.Println(err) os.Exit(1 ) } }
创造性的错误处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package mainimport ( "fmt" "io" "os" ) type safeWriter struct { w io.Writer err error } func (sw *safeWriter) writeln(s string ) { if sw.err != nil { return } _, sw.err = fmt.Fprintln(sw.w, s) } func proverbs (name string ) error { f, err := os.Create(name) if err != nil { return err } defer f.Close() sw := safeWriter{w: f} sw.writeln("Errors are values." ) sw.writeln("Don’t just check errors, handle them gracefully." ) sw.writeln("Don't panic." ) sw.writeln("Make the zero value useful." ) sw.writeln("The bigger the interface, the weaker the abstraction." ) sw.writeln("interface{} says nothing." ) sw.writeln("Gofmt's style is no one's favorite, yet gofmt is everyone's favorite." ) sw.writeln("Documentation is for users." ) sw.writeln("A little copying is better than a little dependency." ) sw.writeln("Clear is better than clever." ) sw.writeln("Concurrency is not parallelism." ) sw.writeln("Don’t communicate by sharing memory, share memory by communicating." ) sw.writeln("Channels orchestrate; mutexes serialize." ) return sw.err } func main () { err := proverbs("proverbs.txt" ) if err != nil { fmt.Println(err) os.Exit(1 ) } }
新的错误 当函数接收到不正确的形参,你可以创建并返回新的错误来通知调用者出现了什么问题
编写一个9*9的网格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package mainimport ( "errors" "fmt" ) const rows, columns = 9 , 9 type Grid [rows][columns]int8 func (g Grid) Set(row, column int , digit int8 ) error { if !inBounds(row, column) { return errors.New("下标越界" ) } g[row][column] = digit return nil } func inBounds (row, column int ) bool { if row < 0 || row >= rows { return false } if column < 0 || column >= columns { return false } return true } func main () { var g Grid err := g.Set(10 , 0 , 5 ) if err != nil { fmt.Printf("An error occurred:%v\n" , err) } }
不要惊恐 go语言有一种类似于异常的机制,panic,panic会在退出程序前执行所有被延迟的操作,而os.Exit()则不会这么做
1 2 3 4 5 6 7 8 9 10 11 12 13 package mainimport "fmt" func main () { defer func () { if e := recover (); e != nil { fmt.Println(e) } }() panic ("i forget my dogs!" ) }