How To Handle Errors In Google Go
| 18th October 2010 |
Multiple return values
A function in a Go program can return multiple values. Some of the Go library functions make use of this to specify an error as one of the return values. This method of returning an error value along with the normal return value can be used with your own functions as well.
package main
import "os"
import "fmt"
func myfunc() int{
filename := "error.txt"
file, err := os.Open(filename, os.O_RDONLY, 0) //the err
if err != nil{
fmt.Println(err.String())
return -1
}
var b []byte
file.Read(b)
return 0
}
func main(){
myfunc()
}
err is of type os.PathError that provides a String() function that generates an informative string.
i.e. err.String() will return the string,
open error.txt: no such file or directory
Panic
Sometimes the error is unrecoverable and the program simply cannot continue. Go provides a built-in function panic() that creates a run-time error that stops the program.
package main
import "os"
func myfunc() int{
filename := "error.txt"
file, err := os.Open(filename, os.O_RDONLY, 0)
if err != nil{
panic(err.String())
}
var b []byte
file.Read(b)
return 0
}
func main(){
myfunc()
}
Output as a result of the panic is as shown below. Seen is the string passed as argument into panic. Also seen is the stack as it unwinds due to the panic.
panic: open error.txt: no such file or directory panic PC=0xc4b044 runtime.panic+0xa9 /home/kevin/go/src/pkg/runtime/proc.c:1020 runtime.panic(0x0, 0xc4b074) main.myfunc+0xa0 /home/kevin/programs/error.go:13 main.myfunc(0x8061b98, 0xc471f0) main.main+0x1f /home/kevin/programs/error.go:20 main.main() mainstart+0xf /home/kevin/go/src/pkg/runtime/386/asm.s:83 mainstart() goexit /home/kevin/go/src/pkg/runtime/proc.c:145 goexit()
Recover
Panic can be called explicitly in our program or it may be called implicitly due to run-time errors such as indexing an array out of bounds or failing a type assertion. It immediately stops execution of the current function and begins unwinding the stack of the goroutine, running any deferred functions along the way. If that unwinding reaches the top of the goroutine’s stack, the program dies.
The built-in function recover can be used to regain control of the goroutine and resume normal execution. A call to recover stops the unwinding and returns the argument passed to panic. Because the only code that runs while unwinding is inside deferred functions, recover is only useful inside deferred functions.
Recover can help us simplify error handling in complex software and to exit a program cleanly.
package main
import "fmt"
import "os"
func myfunc() int{
filename := "error.txt"
file, err := os.Open(filename, os.O_RDONLY, 0)
if err != nil{
panic(err.String())
}
var b []byte
file.Read(b)
return 0
}
func main(){
defer func() {
if p := recover(); p != nil {
fmt.Println("myfunc failed:", p)
}
}()
myfunc()
}
In this example, if there is a panic in myfunc(), the result will be logged and the goroutine will exit cleanly without disturbing the others. There’s no need to do anything else in the deferred closure; calling recover handles the condition completely.
Ouput as a result of the panic is as shown below
myfunc failed: open error.txt: no such file or directory


