continue, break, & fallthrough

Continue and break have caused me a fair amount of consternation during my looping career. I come up with a reason to use it, and I’m forced to use Go Playground in order to prove their functionality to myself before I trust it. By writing down their functionality, I hope to both end these google searches for myself, and also provide us both with a tab that we will inevidably be using.

First off, continue and break are both ways that you can act to affect how a loop will behave while you’re in the loop, probably with other control flow accompanying it. They differ in their functionality in whether another iteration of the loop will run.

Continue

Let’s say we have a function like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func main() {
	i := 0
	for i < 5 {
		if i == 2 {
			fmt.Println("made it to 2!")
			continue
		}
		fmt.Println(i)
		i++
	}
}

What do you expect to happen? This code will print 0, 1, then get stuck on made it to 2!, and log forever. Whoops. The keyword continue will skip the rest of the loop statement and go to the next iteration of the for loop.

The usefulness of the continue can be seen in the following code snippet. purpose is to send emails to recipients.

 1package main
 2
 3import (
 4	"errors"
 5	"fmt"
 6	"log"
 7)
 8
 9func main() {
10
11	var recips []recipient
12	recips = createRecips()
13
14	for _, recip := range recips {
15		if recip.email == "" {
16			fmt.Printf("could not send an email to %s\n", recip.name)
17			continue
18
19		}
20
21		if err := sendEmail(recip.email); nil != err {
22			log.Fatal(err)
23
24		}
25
26	}
27
28	fmt.Println("emails done sending")
29}

On line 17, you can see where the continue statement lies in wait. This statement allows us to continue iterating over the recipients and avoid triggering an error deeper in the code by first making sure that we had an email for the user before attempting to send the sendEmail() function our value. This check could also be done within the function, but I find it to be safer to not hand a function deformed data if you can help it, and makes the code more resilient if you end up refactoring this code with a different package that contains a sendEmail() function.

As a sidenote, this example should be taken on face value with much room for improvement in production code. For example, in this example case, we’re just logging that the email couldn’t be sent on line 16, but in reality, you’d probably want to add the recipient instance to some sort of error map that’s returned to us at the end of the program execution.

Break

Taking the first example, and substituting a break in for the continue, we find that it yields a result that if far less troll-like of me.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func main() {
	i := 0
	for i < 5 {
		if i == 2 {
			fmt.Println("made it to 2!")
			break
		}
		fmt.Println(i)
		i++
	}
}

The difference between this code snippet and the last is that it will print 0, 1, made it to 2!, then exit the loop completely.

I’ve found only a few instances where using a break statement is useful, because breaking out of the loop generally occurs due to an error. An instance that I’ve used it in is when I’ve found an item in a slice that I’m looking for, and there’s no point in continuing. If you have others, I’d love to hear how you’ve used it!

Fallthrough

A cousin of both of these is fallthrough, which is used in switch statements. What do you expect to happen in the following snippet?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
   	i := 2
	switch {
	case i == 2:
		fmt.Println("i is equal to 2!")
		fallthrough
	case i < 1:
		fmt.Println("i is less than 1!")
	case i > 1:
		fmt.Println("i is greater than 1!")

	}

The utility of fallthrough fits the name: it will print i is equal to 2!, then i is less than 1!. This is an extremely contrived example. I don’t know where using fallthrough would be more readable than other options, but I do see where it could save a few lines of code. However, I’m unsure if this only makes the code harder to read, and the programmer is better off typing a few more characters if it means being explicit.

Summary