Tiny func to close io.Closer safely
When you finish file processing or reading HTTP response, you should call Close() func and do exit processing. You may use a simple call with defer.
func hoge() error {
f, err := os.Open("/path/to/file")
if err != nil {
return err
}
defer f.Close()
...
}But this has some problems.
The type of value is error. That is, the process may fail, and you sometime want to log the error message.
kisielk/errcheck is a bit strict linter. It forbids to ignore return values like this. You can avoid this by using _ and illustrating the existence of return values,
defer func() { _ = f.Close() }()or it is also good not to use defer.
func hoge() error {
f, err := os.Open("/path/to/file")
if err != nil {
return err
}
...
return f.Close()
}People issue this many times (#55, #77, #101), but they are all rejected. The author may think error's should be checked explicitly.
This package solves them all.
func hoge() (err error) {
f, err := os.Open("/path/to/file")
if err != nil {
return err
}
defer closer.Close(f, &err)
...
}That's it! This code manages the exit processing and can report the error when it occurs.
The point is the signature: (err error). The defer block can overwrite the value err -- the named return value. You may not have used named return values. You need (almost) not to change how to write functions.
func fuga() (_ []int, err error) {
f, err := os.Open("/path/to/file")
if err != nil {
return nil, err
}
defer closer.Close(f, &err)
...
return result, nil
}There are no problems when the function have multiple return values. You can use _ as the values that do not need names.
You sometime want to clean up after opening tempfiles.
func hogefuga() error {
f, err := ioutil.TempFile("", "hogefuga")
if err != nil {
return err
}
defer os.Remove(f.Name()) // This ignores the error!
...
return nil
}You cannot use close.Close() because os.Remove() is not io.Closer. You can use more general function: closer.Check().
func fugahoge() (err error) {
f, err := ioutil.TempFile("", "fugahoge")
if err != nil {
return err
}
defer closer.Check(func() error { return os.Remove(f.Name()) }, &err)
...
return nil
}- Don’t defer Close() on writable files – joe shaw
- An entry to explain a matter when you do not read the return value of
Close().
- An entry to explain a matter when you do not read the return value of
github.com/src-d/go-git/utils/ioutil.CheckClose()- This idea of here is the implementation of this repo. But it has no tests and the repo is too huge for the use of this use. So I created this package.