Functions & multiple returns
You've written Go functions since 0.2: the types go after the names, the return type goes after the brackets, and neighbouring parameters can share a type. This lesson covers the part PHP never had, which is returning more than one value, plus a few PHP habits that don't make the trip.
Tip
You may have noticed that exercise functions start with a capital letter, as in Split and Board, while lesson examples like split don't. A capital letter is Go's version of public, and lesson 1.11 explains it properly. Inside a single package, both work the same.
Returning more than one value
In PHP, a function that needs to hand back two things returns an array, and the caller unpacks it: [$hours, $mins] = split(135);. It works, but the array is a wrapper you build only to tear it down again, and nothing checks that it really has two elements.
Go functions can simply return several values. List the types in brackets:
func split(minutes int) (int, int) { return minutes / 60, minutes % 60 } hours, mins := split(135) // 2, 15
Each value has its own type, and the compiler checks both ends. The function must return exactly two ints. The caller must receive exactly two values.
That second rule is the one that bites. h := split(135) doesn't quietly keep the first value. It's a compile error, assignment mismatch: 1 variable but split returns 2 values. When you only want some of the values, catch the rest with the blank identifier from 1.1:
_, mins := split(90) // just the 30
There's one shortcut: you can pass every result of one call straight into another, as long as the counts line up. fmt.Println(split(135)) prints 2 15, because Println takes any number of arguments. The exercise's main does exactly this.
Tip
You'll see two return values everywhere in Go, and the second one is very often an error: n, err := strconv.Atoi("42"). That's how Go reports failure without exceptions, and Unit 4 is all about it. For now, the thing to remember is that Go makes you receive the error, even if you then throw it away with _.
Named results
You can give the results names, and they then work as documentation:
func split(minutes int) (hours, mins int) { hours = minutes / 60 mins = minutes % 60 return }
Named results are declared for you at their zero values, so the function can assign to them, and a bare return sends back whatever they hold. That bare return is called a naked return. In a three-line function it's fine. In a forty-line function, the reader has to scroll up to work out what's being returned, so most Go code names results for the docs but still writes return hours, mins.
Variadics
PHP's int ...$legs exists in Go too, with the dots in front of the type:
func total(legs ...int) int
Inside the function, legs is a slice of ints, Go's growable list (all of Unit 2 is about them). len(legs) gives you the count, and the Interchange tab shows a loop over one, ahead of lesson 1.9.
To pass a slice you already have, spread it with the dots after it: total(journey...). Same three dots as PHP, at the other end. Your fingers will type ...journey for about a week.
What Go leaves out
Mind the gap
No default parameter values, no named arguments, no overloading. function board(string $dest, int $platform = 1) has no Go equivalent. Every call passes every argument, in order, and two functions can't share a name. When you'd reach for an optional parameter, Go code writes a second, more specific function (board and boardPlatform), or takes a struct of options (structs arrive in 1.4).
It sounds restrictive, and the first time you miss PHP 8's named arguments, it is. The upside is that a Go call site always tells you everything. Quick: what's the fourth parameter of htmlspecialchars(), and what does it default to? In Go you'd never need to know, because it would be sitting right there in the call.
Recap
- A function can return several values:
func split(m int) (int, int). The caller must receive all of them, using_for the ones it doesn't want. - Named results document what comes back. Avoid naked returns in anything longer than a few lines.
- Variadics:
legs ...intin the signature, a slice inside, andtotal(journey...)to spread a slice in. - No defaults, no named arguments, no overloading. Write a second function or pass a struct.