What’s the best way of emulating a try/catch in golang . Consider the psuedo-code in java to execute a bunch of sql
db.Attach(dbFile)
try {
db.Exec(sql1);
db.Exec(sql2);
db.Exec(sql3);
} catch (SQLExecption e) {
throw new Error("sql error in executing " + dbFile + " ", e);
}
to do this in golang, I would have to do something like
db.Attach(dbFile)
var err error
if err = db.Exec(sql1); err != nil {
log.Panic(fmt.Sprintf("error in attaching db %s error : %s", dbFile, err))
}
if err = db.Exec(sql2); err != nil {
log.Panic(fmt.Sprintf("error in attaching db %s error : %s", dbFile, err))
}
if err = db.Exec(sql3); err != nil {
log.Panic(fmt.Sprintf("error in attaching db %s error : %s", dbFile, err))
}
I can shorten it to something like
db.Attach(dbFile)
db.MustExec(sql1)
db.MustExec(sql2)
db.MustExec(sql3)
But I won’t be able to get information about the attached db in the error message. How do I achieve the effect of try/catch without being too verbose, short of putting the SQL statements in a splice and looping through it.
Thanks in advance.
4
In the Go language, you can catch panics like catching exceptions.
Although it’s not recommended to replace the manual error handling, but it’s possible.
func catchme() {
panic("oh no!")
}
func main() {
defer func() {
if err := recover(); err != nil {
log.Println("panic occurred:", err)
}
}()
catchme()
}
Looking at typical (C++, Python, Java..) exceptions, there are two aspects to the exception handling:
- The “regular” value is not returned. Instead, the function gives back an exception.
- The control flow takes a different path.
You can do these things separately in Go.
For the returnvalue vs. exception as function result, the typical Go idiom is to return a tuple. If you return e.g. a string
in languages with exceptions, in Go you return string, error
instead. If your function succeeds (the return
equivalent), you return "some string", nil
in Go. In case of failure, you return nil, some_error
instead. The fmt.Errorf()
function helps creating these error
instances. Also, you guessed it, the exception class is replaced with Go’s error
.
For the control flow, there is nothing inherent that you could use. The idiom is to check the returned tuple whether its error
element is not nil
. If so, you just return to the calling function, forwarding the returned error. If you want to return a more specific error
implementation (equivalent to exception wrapping/chaining), you just create it with the existing error
.
This may seem annoying, because it only works well with return
and not locally, but remember that you can always use e.g. defer
to define epilogue code and also that you can use local functions (“closures”) to structure your code.
I wrote a library to that avail : https://gitlab.com/reda.bourial/catch
Here is how you can catch errors :
panicked,err:=Panic(func(){
// You SQL queries go here
})
``
3