1. 程式人生 > >5 Gotchas of Defer in Go (Golang) — Part III

5 Gotchas of Defer in Go (Golang) — Part III

#4— Releasing the same resource

The section third above has one caveat: If you try to close another resource using the same variable, it may not behave as expected.

Example

This innocent looking code tries to close the same resource twice. Here, the second r variable will be closed twice. Because, r variable

will be changed for the second resource below.

func 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.txt
closing resource #another-book.txt

Why

As we’ve seen before, when defers run, only the last variable gets used. So, f variable will become the last one (another-book.txt). And, both defers will see it as the last one.

Solution

func 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.txt
closing resource #book.txt