[Go language] uses defer and a well-known return value to implement automatic rollback of initialization failure

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed. The initialization of a slightly more complex program involves multiple modules, which should be rolled back to the other modules that have already been initialized after the initialization of any of the modules has failed. One by one It is easy to make the initialization error handling verbose, contain duplicate code, or the execution path jump is not easy to read and error prone. The mechanism of defer and well-known return values provided by the go language makes it easier to solve this problem and make initialization error handling concise and clear.
Let's take a look at a common error-handling code: Func Initialize () error {
var err errorerr = init_a () if err! = Nil {
return err
}err = Init_b () if err! = Nil {
uninit_a ()
return err
}
err = Init_c ()
If Err! = Nil {
uninit_b ()
uninit_a (
)
return err
}
err = init_d ()
If Err! = Nil {
uninit_c ()
uninit_b (
)
uninit_a (
)
return err
}
return Nil
It can be seen that such a deal is very troublesome, uninit_a () such a statement to write time and time again.
Then try Goto:func Initialize () error {
var err errorerr = init_a () if err! = Nil {
goto _err
}err = Init_b () if err! = Nil {
goto _ua
}
err = Init_c ()
If Err! = Nil {
goto _ub
}
err = init_d ()
If Err! = Nil {
goto _UC
}
_UC:
Uninit_c ()
_ub:
Uninit_b ()
_ua:
uninit_a ()
_err:
Return Err
_exit:
return Nil
This is better than the previous one, without having to write Uinit_a (), Uinit_b () ... The But there are also obvious drawbacks to using goto:
    1. Label too much, see the dizzy
    2. With Goto, the execution process jumps away, causing the mind to break and jump
    3. The initialization of the variable should be placed at the beginning of the function, not in the place where it was used, or it would compile an error "jumps over declaration".
So, Goto is not a good plan either. Some people say that you can define an array of functions, do initialization and error rollback in loops: Func Initialize () error {
inits: = []func () error {init_a, init_b,init_c, init_d}uinits: = []func () error {uninit_a,uninit_b, Uninit_c, UnInit _d}for I: = 0; I <len (inits); i++ {
err: = Inits[i] () if err! = Nil {
For
J: = I-1; J >= 0;j--{
Uninit[j] ()
}
return Err
}
}return Nil
The scheme looks very concise and beautiful. But there is also a fatal drawback: it is not a generic solution. Because Init_a (), Init_b (),... Their function signatures are not necessarily the same, and may even have dependencies: for example, Init_b () requires a variable as a parameter, and this variable is returned by Init_a (). This time there is no way to deal with the unification, so this scheme is not feasible.
But with defer and a well-known return value, you can handle this problem nicely: Func Initialize () (err error) {//Note here defines an err as a return value variable
rollback: = Func (UnInit func ()) {
If Err! = Nil {
UnInit ()
}
}err = init_a () if err! = Nil {
return err
}
defer rollback (uninit_a)
err = Init_b ()
If Err! = Nil {
return err
}
defer rollback (uninit_b)
err = Init_c ()
If Err! = Nil {
Return Err
}
defer rollback(uninit_c)
return Init_d ()
}
It's simple and beautiful, isn't it? There may be one small question: What about the inconsistent parameter signatures of the inverse initialization function? The answer is:
    1. In most cases, the parameter signatures of the inverse initialization function are the same
    2. Even if the individual is not the same, in the defer can also be wrapped in closures, there is no burden. For example:
defer rollback (func () {uninit_b ()})

It's that simple.
When discussing related issues at Golang-nut (need to turn over the wall), Ian Lance Taylor,minux, Nigeltao, and others were enthusiastic and helpful, thanks to them as well as to the passionate and vibrant Golang community. April civilians pointed out that the last piece of code in the text was wrong (now amended), and thank you for that.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.