Tom Carrick
Tom Carrick

Reputation: 6616

Custom error handling in Go

I've been reading this blog post but I'm still not convinced I know exactly what to do to get custom errors that I can return from my functions and handle outside of them.

This is what I'm currently doing:

func doSomething() int {
    x := 0
    // Do something with x.
    ...
    if somethingBadHappened {
        return -1
    }
    if somethingElseBadHappened {
        return -2
    }
    return x
}

This is what I'd like to be doing:

func doSomething() int, ? {
    ...
    if somethingBadHappened {
        return ?, err
    }
    if somethingElseBadHappened {
        return ?, err2
    }
    return x, nil
}

But I'm not exactly sure how, and what to replace those question marks with.

Upvotes: 4

Views: 2712

Answers (2)

zzzz
zzzz

Reputation: 91399

I would turn

func doSomething() int, ? {
        ...
        if somethingBadHappened {
                return ?, err
        }

        if somethingElseBadHappened {
                return ?, err2
        }

        return x, nil
}

into

func doSomething() (r int, err error) {

        ...

        if somethingBadHappened {
                err  = err1 // Whatever satisfies the `error` interface
                return
        }

        if somethingElseBadHappened {
                err = err2 // dtto
                return
        }

        return x, nil
}

IOW, at the call site it is idiomatic* to ignore, never use or rely on, any other returned value if err != nil, so just don't care if r above has had been assigned some intermediate value or not.

(*) In the first approximatiom, i.e. if not stated otherwise. E.g. an io.Reader explicitly declares it can return both err == io.EOF and valid data at the same time:

When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read. It may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. An instance of this general case is that a Reader returning a non-zero number of bytes at the end of the input stream may return either err == EOF or err == nil. The next Read should return 0, EOF regardless.

Upvotes: 4

kdar
kdar

Reputation: 151

You don't really need to return an int if you don't want to. You can do something like:

func doSomething() error {
  ...
  if somethingBadHappened {
      return errors.New("something bad happened")
  }
  if somethingElseBadHappened {
      return errors.New("something else bad happened")
  }
  return nil
}

or if you want to return ints

func doSomething() (int, error) {
  ...
  if somethingBadHappened {
      return -1, errors.New("something bad happened")
  }
  if somethingElseBadHappened {
      return -2, errors.New("something else bad happened")
  }
  return x, nil
}

be sure to import "errors" at the top.

If you want to test whether you got an error, you can do

x, err := doSomething()
if err != nil {
  log.Println(err)
}

Upvotes: 8

Related Questions