This is a creation in Article, where the information may have evolved or changed. >: A total of four articles, this article is the third article of the same series-[Part I] (https://studygolang.com/articles/12061)-[Part II] (https://studygolang.com/ articles/12136) This article will focus on some tips on using defer if you don't have a clear understanding of defer's basic operations, please read this article first (https://blog.learngoprogramming.com/ GOLANG-DEFER-SIMPLIFIED-77D3B2B817FF) (translated by Gctt https://studygolang.com/articles/11907). # # #1--using recover outside of the deferred call function you should always call ' recover () ' Inside the deferred function, and ' Recover () ' will not catch the exception when a *panic* exception occurs, and ' *defer* ' recove The return value of R () ' will be *nil*. Example ' Gofunc do () {Recover () Panic ("Error")} ' ' Output *recover* did not catch the exception successfully. The ' Panic:error ' # # # solution can avoid this problem by using ' recover () ' inside the deferred function. ' Gofunc do () {defer func () {r: = Recover () fmt. Println ("Recovered:", R)} () Panic ("Error")} ' output ' ' Recovered:error ' ' # # #2--use defer in the wrong place this trap comes from this [50 Shadow of Go] (http ://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/#anameclose_http_resp_ Bodyaclosinghttpresponsebody). Example when ' http. Get ' throws an exception when it fails. "' Gofunc do () error {res, err: = http. Get ("http://notexists") defer res. Body.close () IF Err! = Nil {return err}//. Code...return nil} ' output ' ' Panic:runtime error:invalid memory address or nil pointer dereference ' ' # # # what happened? Because here we do not check whether our request is executed successfully, when it fails, we access the empty variable *res* in *body*, and therefore throw an exception # # # solutions Always use *defer* under a successful resource allocation, which means: when and only if * http. Get* uses *defer* ' Gofunc do () error {res, err: = http when successful execution. Get ("http://notexists") if res! = Nil {defer res. Body.close ()}if err! = Nil {return err}//. Code...return nil} ' ' In the above code, when there is an error, *err* will be returned, otherwise the *res will be closed when the entire function returns. body*. # # # Next Note 1 here, you also need to check whether the value of *resp* is *nil*, this is *http. A warning in the get*. Normally, when an error occurs, the returned content should be empty and the error will be returned, but when you get a redirect *error*, the *resp* value will not be *nil*, but it will return the error. The above code guarantees that the *body* will be closed anyway, and if you do not intend to use the data, you will also need to discard the data you have received. more [details] (http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/#anameclose_http_resp_ Bodyaclosinghttpresponsebody). # # #3-Simply delegating clean logic to *defer* without checking for errors does not mean that the release of the resource is foolproof, and you may miss out on useful error messages to keep some potential problems out of the way. # # # # here, ' F.close () ' may return an error, but this error will be ignored by us ' gofunc do () error {f, err: = OS. Open ("Book.txt"If err! = Nil {return err}defer f.close ()//. Code...return nil} ' # # # Improved It's best to check for possible errors instead of just handing them over to *defer*, you can write the code inside the *defer* as a helper function to simplify our code, which is not simplified for ease of interpretation. "' Gofunc do () error {f, err: = OS. Open ("Book.txt") if err! = Nil {return err}defer func () {if err: = F.close (); Err! = nil {//log etc}} ()//. Code...return nil} ' # # # and then improve you can also return errors within *defer* by naming the return variable. ' Gofunc do (err error) {f, err: = OS. Open ("Book.txt") if err! = Nil {return err}defer func () {if ferr: = F.close (); Ferr! = Nil {err = Ferr}} ()//. Code...return nil} ' # # # 2 You can use this [package] (https://godoc.org/github.com/pkg/errors) to integrate multiple different errors, which is very necessary because of the *f in defer. Close* may overwrite previous errors and wrap multiple errors together to write all error messages to the log, which can be more relied upon to diagnose the problem. You can also use this [package] (Https://github.com/kisielk/errcheck) to see where you missed the error that should have been checked. # # #4-releasing the same resources there is a small warning in the third section: If you try to use the same variable to free up different resources, this operation may not work properly. For example, this seemingly innocuous code tries to close the same resource for the second time. The second * variable f* will be closed two times, because the * f variable * will change its value due to the second resource ' Gofunc do () error {f, err: = OS. Open ("Book.txt") if err! = Nil {return err}defer func () {if err: = F.close (); Err! = Nil {//log etc}} ()//. CODE...F, err = os. Open ("Another-book.txt") if err! = Nil {return err}defer func () {if err: = F.close (); Err! = nil {//log etc}} () return nil} ' Output ' ' Closing resource #another-book.txtclosing resource #another-book.txt ' # # # What happened as we saw when the deferred function was executed, Only the last variable will be used, so the *F variable * will be the last resource (Another-book.txt). And two *defer* will use this resource as the last resource to close the # # # solution ' Gofunc do () error {f, err: = OS. Open ("Book.txt") if err! = Nil {return err}defer func (f io. Closer) {if err: = F.close (); Err! = nil {//log etc}} (f)//. CODE...F, err = os. Open ("Another-book.txt") if err! = Nil {return err}defer func (f io. Closer) {if err: = F.close (); Err! = nil {//log etc}} (f) return nil} ' output ' ' Closing resource #another-book.txtclosing Reso Urce #book. txt "You can also use functions to avoid the above problems, refer to me in [here] (https://blog.learngoprogramming.com/ gotchas-of-defer-in-go-1-8d070894cb01#ac69) Talk about the open/closed mode. # # #5--panic/recover will get and return any type you may think you always need to go to *panic* *string* or *error* type of data # # # passed in string ' Gofunc errorly () {Defer FU NC () {FMT. PRintln (Recover ())} () if badhappened {panic ("Error Run Run")}} ' output ' "Error Run Run" ' # # # incoming error ' "' Gofunc errorly () { Defer func () {fmt. Println (Recover ())} () if badhappened {panic (errors. New ("Error Run Run")}} ' output ' "Error Run Run" ' # # # passed in any type as you can see *panic* receive *string* and [Error type] (https://golang.org/ pkg/builtin/#error). This means that you can actually pass "any type" of data to panic and be able to use *recover* in *defer* to get this data. ' ' Gotype myerror struct {}func (myerror) string () string {return ' Myerror there! '} Func errorly () {defer func () {fmt. Println (Recover ())} () if badhappened {panic (myerror{})}} ' # # # # # # # # # # # # # # # # # # # # # # This is because *panic* 's function signature shows that it can receive the *interface{}* type, and we can interpret it as "any type" in Go, which is *panic* 's signature ' Gofunc Panic (v interface{}) ' *recover* The signature ' Gofunc recover () interface{} ' so basically it will run like this "panic (value), Recover ()," *recover* "will put the incoming *panic* The value returned out of this part is first over, we see part four!
Via:https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-iii-36a1ab3d6ef1
Author: inanc Gumus Translator: yujiahaol68 proofreading: polaris1119
This article by GCTT original compilation, go language Chinese network honor launches
This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove
996 Reads