Drills — write slice functions
Slices have to be written, not just read. Five drills on []int, easy to harder. Write each function, run it on the examples, compare with the solution. (We have slices, range, append, len and if — no maps yet, and none of these need one.) Drill 4 has a twist worth your full attention.
1 (easy) — sum. Add every number in the slice (range + an accumulator).
sum([]int{1, 2, 3, 4}) → 10
func sum(nums []int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
2 (easy) — countAbove. How many numbers are strictly greater than min?
countAbove([]int{5, 1, 9, 3}, 4) → 2
func countAbove(nums []int, min int) int {
count := 0
for _, n := range nums {
if n > min {
count++
}
}
return count
}
3 (medium) — evens. Return a new slice with only the even numbers. This is the append-to-build pattern.
evens([]int{1, 2, 3, 4, 5, 6}) → [2 4 6]
func evens(nums []int) []int {
out := []int{}
for _, n := range nums {
if n%2 == 0 {
out = append(out, n)
}
}
return out
}
4 (medium) — doubleAll, and the twist. Double every number in place — no return value. Then check the caller's slice:
func doubleAll(nums []int) {
for i := range nums {
nums[i] *= 2
}
}
xs := []int{1, 2, 3}
doubleAll(xs)
fmt.Println(xs) // [2 4 6] — the caller's slice DID change!
Stop and compare this with lesson 4. A struct passed to a function is copied, so changes are lost unless you return them. A slice is different: it's a small header pointing at a shared backing array, so writing nums[i] reaches straight through to the caller's data. Same for i := range + index rule as the menu loop — but now it's crossing a function boundary, and that surprises people. (One caveat: this holds for changing existing elements. append may move the data to a new array, so an append inside the function would not show up outside — that's why we always write xs = append(xs, ...).)
5 (harder) — maxOf. Return the largest number and an ok flag — because an empty slice has no maximum to return.
maxOf([]int{3, 7, 2}) → 7, true maxOf([]int{}) → 0, false
func maxOf(nums []int) (int, bool) {
if len(nums) == 0 {
return 0, false
}
best := nums[0]
for _, n := range nums {
if n > best {
best = n
}
}
return best, true
}
The len(nums) == 0 guard isn't optional politeness — nums[0] on an empty slice is a panic. The (value, ok) pair lets the caller tell "the max is 0" from "there was nothing".
Tip. Run each against the examples, and pay off drill 4 by printing
xsbefore and after. These pure functions are, again, exactly whatgo testlocks down in lesson 13.