Multiple return values

func (file *File) Write(b []byte) (n int, err error)


Named result parameters

The names are not mandatory but they can make code shorter and clearer: they’re documentation.
When named, they are initialized to the zero values for their types when the function begins.
func nextInt(b []byte, pos int) (int, int)
func nextInt(b []byte, pos int) (value, nextPos int) {


Defer

Go’s defer statement schedules a function call (the deferred function) to be run immediately before the calling function returns.

  1. // Contents returns the file's contents as a string.
  2. func Contents(filename string) (string, error) {
  3. f, err := os.Open(filename)
  4. if err != nil {
  5. return "", err
  6. }
  7. defer f.Close() // f.Close will run when we're finished.
  8. var result []byte
  9. buf := make([]byte, 100)
  10. for {
  11. n, err := f.Read(buf[0:])
  12. result = append(result, buf[0:n]...) // append is discussed later.
  13. if err != nil {
  14. if err == io.EOF {
  15. break
  16. }
  17. return "", err // f will be closed if we return here.
  18. }
  19. }
  20. return string(result), nil // f will be closed if we return here.
  21. }

two advantages:

  • First, it guarantees that you will never forget to close the file;
  • Second, it means that the close sits near the open, which is much clearer than placing it at the end of the function.

The arguments to the deferred function are evaluated when the defer executes, not when the call executes.
Deferred functions are executed in LIFO order.

  1. for i := 0; i < 5; i++ {
  2. defer fmt.Printf("%d ", i)
  3. }
  4. // 4 3 2 1 0 to be printed