func someSQLStuff() {
tx, err := createTx()
defer func() {
if err != nil {
tx.Rollback()
log(err)
} else {
tx.Commit()
}
}()
rows, err = tx.QueryContext( ... )
// more SQL
}
Basically, function-scoped cleanup. Like closing opened files. func f(i interface{}) {
if closable, ok := i.(closable); ok {
defer closable.close()
}
// do stuff with i, maybe other casts, etc
}
There aren't many nice options for "if I can call X, defer a call to X" aside from shoving it into an `if`, where it'd be captured by that scope. I mean, you could do something like deferrable := func(){}
if closable {
deferrable = closable.close
}
defer deferrable()
but imagine doing that every time. It'd work, sure, but it'd also be more annoying. func closeIfNecessary(object interface{}) {
closable, needsClosing := object.(closable)
if needsClosing {
closable.close()
}
}
And then just do: func f(i interface{}) {
defer closeIfNecessary(i)
...
}
Doing it this way also saves you boilerplate by factoring the downcast out into a separate function.If you can't call it unless [some other conditions], it goes back to the same kind of problem though. "closable" may not be a good choice on my part, as they're often called unconditionally.