What the code is supposed to do
The function printEvenNumbers takes a slice nums and should print the even numbers from it, one per line. For the call printEvenNumbers([]int{2, 1, 0, 4, 3}), the expected output is 2, 0 and 4, in the order they appear in the slice.
The code you start with compiles, but it prints the word even twice instead:
func printEvenNumbers(nums []int) {
for _, num := range nums {
if num % 2 == 1 {
fmt.Println("even")
}
}
}
// Do not change this code:
func mainFunction() {
printEvenNumbers([]int{2, 1, 0, 4, 3})
}
What goes wrong
There are two separate mistakes, both inside the loop.
The test selects the wrong numbers
The operator % gives the remainder after division. An even number divides by 2 with nothing left over, so its remainder is 0. An odd number leaves remainder 1. The condition num % 2 == 1 is therefore true for odd numbers. In the example, that is 1 and 3, which is exactly why the output has two lines: one for each odd number in the slice. The even numbers 2, 0 and 4 fail the test and are skipped.
The fix is to compare with 0: num % 2 == 0.
The print shows a word, not the number
The text "even" in quotes is a string literal, and Go prints it exactly as written on every pass. It never looks at num. To print the number, pass the variable itself, without quotes: fmt.Println(num).
Fixing it step by step
- Change the test from
num % 2 == 1tonum % 2 == 0, so that the body runs for even numbers. - Change the print from the string
"even"to the variablenum. - Leave everything else alone. The loop, the signature and the
mainFunctionthat makes the call stay as they are.
The fixed code in Go
func printEvenNumbers(nums []int) {
for _, num := range nums {
if num % 2 == 0 {
fmt.Println(num)
}
}
}
func mainFunction() {
printEvenNumbers([]int{2, 1, 0, 4, 3})
}
Tracing the call: 2 gives remainder 0 and is printed; 1 gives 1 and is skipped; 0 gives 0 and is printed; 4 is printed; 3 is skipped. The output is 2, 0, 4.
A few Go details:
- Zero is even.
0 % 2is 0, so it is printed. - The slice literal.
[]int{2, 1, 0, 4, 3}creates a slice of five integers. The type goes before the braces. - Why
_.rangeyields an index and a value. The index is not needed, and Go would refuse to compile an unused variable, so it is discarded. - Negative numbers. In Go,
%takes the sign of the left operand, so-3 % 2is-1, not 1. That makesnum % 2 == 1a poor odd test for negative numbers, whilenum % 2 == 0is correct for evens of either sign.
How to spot this kind of bug
Read the broken output against the expected one. Two lines of even instead of three numbers tells you two things at once: the count is wrong, so the condition selects the wrong elements, and the content is wrong, so the print isn't showing the variable. When the number of output lines matches the number of elements the test accepts, count how many elements of the input pass it. Here the odd numbers are 1 and 3, which is exactly two lines. Checking the output size against the input is a quick way to separate a faulty condition from a faulty print.
Common mistakes
- Fixing only one of the two bugs. Changing the condition alone would print
eventhree times. Changing the print alone would print 1 and 3. - Putting quotes around
num.fmt.Println("num")prints the word num. - Using
/instead of%. Division gives the quotient, which is not what the test needs. - Using
== 1for odd numbers on negative input. The remainder of -3 divided by 2 is -1, so the test misses it. Compare with 0, or use!= 0for odd.
Checking your fix
With the corrected function, the call in mainFunction prints three lines: 2, 0 and 4. Also try []int{-4, -3, 7}: only -4 is printed.