Functions
You've been writing func main() since the first lesson. Now let's look at
func properly — because Go functions can do a couple of things that may be
new to you, and one of them shapes the entire language.
Parameters and shared types
Types come after names in Go, and consecutive parameters of the same type can share one type annotation:
package main
import "fmt"
func add(a, b int) int {
return a + b
}
func main() {
fmt.Println(add(3, 4)) // 7
}
func add(a, b int) int reads left to right: "add takes a and b, both
int, and returns an int." The Go team chose name-first order because it
stays readable as signatures grow — you always know what a thing is before
what type it is.
Multiple return values
A Go function can return more than one value — no wrapper object, no output parameters, just a parenthesized list of result types:
package main
import "fmt"
func divmod(a, b int) (int, int) {
return a / b, a % b
}
func main() {
q, r := divmod(17, 5)
fmt.Println(q, r) // 3 2
}
This feature is why Go's error handling looks the way it does: functions
return their result and an error, and the caller checks both. You saw a
preview in the if lesson with strconv.Atoi returning (int, error). If
you need only one of the results, assign the other to _, the blank
identifier: q, _ := divmod(17, 5).
Named results
Result values can be given names, which declares them as variables inside the
function and lets a bare return send back their current values:
func divmod(a, b int) (q, r int) {
q = a / b
r = a % b
return
}
Named results shine in one place: documentation. (q, r int) tells the
caller which result is which without reading the body. But bare returns in a
long function force readers to hunt backwards for what's being returned — so
the community's advice is: name results when it clarifies the signature,
and still write return q, r explicitly in all but the shortest functions.
Functions are values
A function can be assigned to a variable and passed around like any other value:
package main
import "fmt"
func main() {
double := func(n int) int { return n * 2 }
fmt.Println(double(21)) // 42
}
Here double holds an anonymous function. This is the seed of a big idea —
passing behavior as an argument — that powers sorting, HTTP handlers, and
goroutines later in the book. For now, just know the door exists.
The exercise combines this lesson with the last three: loop over a slice, branch on comparisons, and return two values at once.
Practice
1. Min and Max
BeginnerImplement
minMaxso it returns both the smallest and the largest value in a slice of ints:func minMax(nums []int) (min, max int)- If the slice is empty, return
0, 0. - If the slice has one element, that element is both the min and the max.
For example,
minMax([]int{3, -1, 7, 0})returns-1, 7.Watch out for one classic bug: don't initialize
minandmaxto0.minMax([]int{5, 8})should return5, 8— but aminthat starts at0would never move. Start both at the first element instead, then loop over the rest with a three-partforloop (nums[i]reads elementi, andlen(nums)gives the length).package main import "fmt" // minMax returns the smallest and largest values in nums. // For an empty slice it returns 0, 0. func minMax(nums []int) (min, max int) { // TODO: implement return 0, 0 } func main() { fmt.Println(minMax([]int{3, -1, 7, 0})) }Sign in to write and run your solution in the browser.
Sign in for hints and the solution.
- If the slice is empty, return