One thing I love from golang is defer
statement, but defer
only work on func
scope.
So, I very often to use it like this
func (s *Something) abc() error {
func() {
s.Lock()
defer s.Unlock()
// don't lock too long
}()
// do something else
if err := func() error {
resp, err := http.Get("https://example.com/api")
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return errors.New("Failed to download")
}
var tmp struct {
Error bool `json:"error"`
Result string `json:"result"`
}
if err := json.NewDecoder(resp.Body).Decode(&tmp); err != nil {
return err
}
if tmp.Error {
return errors.New("API return error")
}
s.somedata = tmp.result
return nil
}(); err != nil {
return err
}
func() {
s.Lock()
defer s.Unlock()
// don't lock too long
}()
// do something else
}
basically, I wrap it into anonymous block func
.
Is it common to use something like this? do any other gophers abuse this fact?
EDIT: Clarification
Okay, it looks like I didn't explain it well, There are 2 things I want to achieve
-
What I want to achieve is to lock mutex as short as possible
func() { s.Lock() defer s.Unlock() // don't lock too long // there is other code here, this func is not an empty func }()
There more than one http.Get in this function, let's say after calling example.com/api I need to call example.com/api2 . We need to close resp.Body as soon as possible, so only one TCP connection is made to this server. AFAIK, http.Get will create another TCP connection if there is another HTTP connection that not closed yet (resp.Body.Close() is not called on previous response).
EDIT 2: more clarification
first and last anonymous function and lock are to sync cache. I implement cache based on map[string]string, so it needs to be sync-ed.
I need to call example.com/api first, and based on the response I need to call example.com/api2 or example.com/api3, and at that time previous http connection must be closed, it can be code like this
resp, err := http.Get("https://example.com/api")
if err != nil {
return err
}
if resp.StatusCode != 200 {
resp.Body.Close()
return errors.New("Failed to download")
}
// process the body
resp.Body.Close()
but you need to explicitly write resp.Body.Close() twice