Functions

Course 1 · Ch 5
Functions: Multiple Returns, Named Returns, and Variadic Parameters
Go functions can hand back more than one value at once — the foundation of Go's entire error-handling style

Every function so far (main) has returned nothing. JavaScript functions return exactly one value — wrapping several values up means returning an array or object instead. Go does something JavaScript can't: a function can return multiple, separate values directly, no wrapping required. This single feature underpins almost every standard-library function in Go, including fmt.Println's lesser-known cousin fmt.Sscanf and error handling throughout the language.

A Basic Function with Types on Both Ends

func add(a int, b int) int { return a + b } fmt.Println(add(3, 4)) // 7

Each parameter's type follows its name (a int), and the return type follows the closing parenthesis () int {) — there's no function keyword equivalent confusion here since Go only has one function syntax, unlike JavaScript's three (Fundamentals Chapter 5).

Shared type shorthand
When consecutive parameters share a type, the type only needs writing once: func add(a, b int) int means exactly the same as func add(a int, b int) int.

Multiple Return Values

func divide(a, b float64) (float64, string) { if b == 0 { return 0, "cannot divide by zero" } return a / b, "" } result, errMsg := divide(10, 2) fmt.Println(result, errMsg) // 5 ""

(float64, string) in the return position declares two separate return values — every return statement inside must supply both. The caller receives both at once with result, errMsg := divide(10, 2), destructuring-style, but without any array or object ever being created.

The error Type — Go's Real Error-Handling Pattern

import ( "errors" "fmt" ) func divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("cannot divide by zero") } return a / b, nil } result, err := divide(10, 0) if err != nil { fmt.Println("Error:", err) } else { fmt.Println("Result:", result) }

This is the real, idiomatic Go pattern, used constantly throughout the language: a function returns its normal result plus an error, which is nil (Go's null) when nothing went wrong. if err != nil immediately after almost every call is so common it's practically a Go signature — this replaces the try/catch pattern from JavaScript Fundamentals Chapter 10 entirely; Go has no exceptions to throw or catch for ordinary error handling.

Named Return Values

func rectangleStats(width, height float64) (area, perimeter float64) { area = width * height perimeter = 2 * (width + height) return // "naked return" — returns area and perimeter automatically } a, p := rectangleStats(5, 3) fmt.Println(a, p) // 15 16

Naming the return values in the function signature (area, perimeter float64) pre-declares them as variables, usable directly inside the function body. A bare return with nothing after it — a naked return — automatically sends back whatever those named variables currently hold. This is mostly a readability tool for short functions; longer functions are usually clearer with an explicit return area, perimeter.

Variadic Parameters — Go's Version of Rest Parameters

func sum(numbers ...int) int { total := 0 for _, n := range numbers { total += n } return total } fmt.Println(sum(1, 2)) // 3 fmt.Println(sum(1, 2, 3, 4)) // 10

...int before the parameter type marks it as variadic — Go's direct equivalent of JavaScript's rest parameter (...numbers) from Intermediate Chapter 1. Inside the function, numbers behaves as a real slice, so range works on it exactly as it did in Chapter 4.

JavaScriptGo
Returns one value (or an array/object of several)func f() (int, string) — returns several, separately
try/catch + throwreturn value, error + if err != nil
function f(...args)func f(args ...int)
No named return conceptfunc f() (result int) { ...; return }

Coding Challenges

Challenge 1

Write a function divide(a, b float64) (float64, error) that returns an error from the errors package if b is 0, otherwise the division result and nil. Call it twice — once with b = 0, once with a real divisor — handling both with if err != nil.

📄 View solution
Challenge 2

Write a function minMax(numbers ...int) (min, max int) using named return values and a naked return, that finds the smallest and largest values among any number of arguments. Call it with at least 5 numbers.

📄 View solution
Challenge 3

Write a function describeNumber(n int) (string, bool) that returns "even" or "odd" as the first value, and whether n is positive as the second (boolean) value. Call it with three different numbers, printing both returned values each time.

📄 View solution

Chapter 5 Quick Reference

  • func name(param type) returnType { } — basic function shape
  • func name() (typeA, typeB) { return a, b } — multiple return values, no wrapping needed
  • error type + nil — Go's standard error pattern; check with if err != nil
  • errors.New("message") — creates a basic error value
  • Named returns: func f() (result type) — pre-declares the variable; "return" alone sends it back
  • Variadic parameters: func f(args ...type) — Go's equivalent of JavaScript's rest parameter
  • No try/catch — error handling is just normal values and normal if statements
  • Next chapter: arrays and slices — Go's two array-like types, and why slices are used almost everywhere