Error handling has been a very controversial area of Go, and people have contributed all sorts of ideas to proposals in that category. Recently, I also found an interesting technical proposal: the left-hand side function; and a new idea for Go+.

## Go’s new proposal: the left-hand side function

With the existing Go1 error handling mechanism, we generally need to write a lot of if err ! = nil logic.

Some people laughingly claim that 50 out of 100 lines of code are the following.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  func main() { x, err := foo() if err != nil { // handle error } y, err := foo() if err != nil { // handle error } z, err := foo() if err != nil { // handle error } s, err := foo() if err != nil { // handle error } } 

So several people in the community came up with the idea of left-handed functions.

We hope to solve the error handling problem by reducing the extra 3 lines of code written each time and achieving a consistent error handling method.

The following proposal was involved.

The new code in the proposal is as follows.

 1  fmt.Errof("%v, %w", a, err) := simple() 

Simplified writing.

 1  errorHandle(err) = io.Copy(w, r) 

A new way of thinking about handling errors is to add a layer (the universal software architecture way of handling them) and use the left-hand function to handle all errors.

## Go+: Error Expressions

A member of the Go-related group: Go+, has also made its own “ErrWrap expressions” error handling solution, which was discussed by a certain number of people in the previous proposal, so you can evaluate it together.

### Introduction to expressions

The core idea is to add a syntactic mechanism of expressions to error handling. As follows.

 1 2 3  expr! // panic if err expr? // return if err expr?:defval // use defval if err 

We’ll expand on them one by one.

The expression expr! checks if valN is zero. If not, it will panic. the corresponding Go code.

 1 2 3 4 5  val1, val2, ..., valN1, valN := expr if valN != nil { panic(errors.NewFrame(valN, ...)) } val1, val2, ..., valN1 // value of expr! 

The expression expr? checks if valN is nil, and if not, it returns an error. Corresponding Go code.

 1 2 3 4 5 6  val1, val2, ..., valN1, valN := expr if valN != nil { _ret_err = errors.NewFrame(valN, ...) return } val1, val2, ..., valN1 // value of expr? 

The expression expr?:defval checks if valN is nil. if not, it uses defval as the value of expr. Corresponding Go code.

 1 2 3 4 5  val1, val2 := expr if val2 != nil { val1 = defval } val1 // value of expr?:defval 

### Demonstration code

Specific sample code.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  import ( "strconv" ) func add(x, y string) (int, error) { return strconv.Atoi(x)? + strconv.Atoi(y)?, nil } func addSafe(x, y string) int { return strconv.Atoi(x)?:0 + strconv.Atoi(y)?:0 } println(add("100", "23"):, add("100", "23")!) sum, err := add("10", "abc") println(add("10", "abc"):, sum, err) println(addSafe("10", "abc"):, addSafe("10", "abc")) 

Output.

 1 2 3 4 5 6 7 8  add("100", "23"): 123 add("10", "abc"): 0 strconv.Atoi: parsing "abc": invalid syntax ===> errors stack: main.add("10", "abc") /Users/xsw/goplus/tutorial/15-ErrWrap/err_wrap.gop:6 strconv.Atoi(y)? addSafe("10", "abc"): 10 

In addition to the optimization of the mechanism for error handling based on expressions, information tracking of the error stack has been added.