Step 1 of 7 · Reading · ~4 min
Learn
Pointers and Errors
Multiple Returns and the error Pattern
A Go function can hand back more than one value at a time. By the end of this lesson you can write a function that returns two results, use a named return, and build the (value, error) pair that the whole standard library speaks.
Two values out of one function
List the return types in parentheses after the parameter list, and separate the returned values with commas:
Returns are positional: the first value in the return lands in the first variable on the left. Nothing is bundled into a tuple or a struct - splitTime really produces two independent ints, and mins, secs := ... catches both. You can take only one of them with the blank identifier you met in the loops lesson:
Naming the returns
You may name the results in the signature. Named results are pre-declared variables, and a bare return sends back whatever they currently hold:
Names document which value is which, so (lo, hi int) beats (int, int) in a signature a reader meets cold. Keep naked returns to short functions: in a fifty-line one, nobody can see what return is returning.
The value-and-error pair
The second result is usually an error, and that is the shape the rest of Go is built on. The convention has four parts:
erroris the last return type.- On success: the real value, and
nil. - On failure: the zero value, and a non-nil error built with
errors.Neworfmt.Errorf. - The caller checks the error before touching the value.
Point 4 is not politeness, it is correctness. The value on the failure path is a real number that means nothing:
Guard first, then use the value. A guard is also what keeps a division alive: on int variables, dividing by one that holds 0 does not produce an error, it kills the program with panic: runtime error: integer divide by zero. Checking before dividing is what turns that crash into a value a caller can handle.
fmt.Errorf formats a message with the usual verbs. Its %w verb is special: it wraps the error you pass, so a caller several layers up can still ask errors.Is(err, os.ErrNotExist) about the original. Reach for %w when you add context to an error you received, and errors.New when the message is a fixed string of your own.
Common mistakes
- Guarding the wrong operand. Testing the left-hand number instead of the divisor makes input
0and5printerror: divide by zero, when a zero dividend divides perfectly well and should printresult: 0. - A non-nil error on the success path.
errors.New("")is still non-nil, so the caller takes the failure branch and printserror:with nothing after it - and a placeholder message left in place printserror: todofor every input. - Computing before guarding. Divide first and the zero-divisor case never reaches your check: the program panics with
integer divide by zeroand prints no line at all. - Expecting division to round. Go truncates toward zero, so
9over-2is-4, not-5and not-4.5. The hidden tests use negative numbers.
Your exercise
Fill in the body of safeDivide so a zero divisor is reported through its error result instead of crashing the program, and any other divisor yields the quotient with no error. main, the input reading and both output lines are already written; the starter's placeholder fails on every call, so valid divisions stay broken until you fix the success path. The most likely slip is checking the wrong one of the two numbers.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…