Go: from zero to your own blog Lesson 6 of 50
Branching and loops in Go: if, else and the only for
The sixth lesson of the Go course. How a program picks between two paths: if, else if and else, comparisons, and the AND, OR and NOT that join them. And the loop — Go has exactly one, the word for, in three shapes: with a counter, on a condition, and endless with a break. The language has no while, no do-while and no foreach.
Why this matters
So far your program does the same thing whatever the values are. To answer differently — to call an article with a thousand views popular and a fresh one new — you need branching.
And to repeat something without writing it out ten times you need a loop. Here Go is unusual: it has one. The words while, do-while and foreach are not in the language — for does all of it, in different shapes.
The whole thing at once
A new folder, go mod init sabaq05, main.go:
package main
import "fmt"
func label(views int) string {
if views >= 1000 {
return "popular"
} else if views >= 100 {
return "being read"
}
return "new"
}
func main() {
fmt.Println(12, "—", label(12))
fmt.Println(340, "—", label(340))
fmt.Println(1500, "—", label(1500))
for i := 1; i <= 3; i++ {
fmt.Println("lesson", i)
}
words := 0
for words < 600 {
words += 200
}
fmt.Println("words so far:", words)
}
Before you run it, and without looking below, say out loud what it will print. Then run it and compare: the difference is exactly where you do not know the language yet.
go run . prints:
12 — new
340 — being read
1500 — popular
lesson 1
lesson 2
lesson 3
words so far: 600
Taking it apart
if: a fork
if views >= 1000 {
The condition is written without round brackets — Go does not need them and nobody puts them in. The body is always in braces, even for a single line: there is no bracket-less short form in the language, and that removes a whole class of mistakes people trip over elsewhere.
Picture it. A fork in the road with a sign. The sign does nothing itself — it only settles which side you drive on. Both roads exist; you take one.
else if and else
The tests run top to bottom and the first one that fits is the one that runs. Order therefore matters: put >= 100 above >= 1000 and a thousand lands in “being read”, because the second test is never reached.
The closing else is optional. There is none in the example: after all the tests there is simply return "new" — the same meaning, one line shorter.
What compares
== equal, != not equal, < > <= >=. The double equals of a comparison and the single equals of an assignment are different things, and Go will not let you confuse them: if views = 1000 does not build.
Conditions join with && for both, || for either, ! for the opposite.
if views >= 100 && views < 1000 {
for with a counter
for i := 1; i <= 3; i++ {
Three parts separated by semicolons: start a counter, test while, do after each turn. i++ adds one.
Picture it. The three things you tell a storeman: which shelf to start at, how far to count, and how many to step by. Give him all three and he walks the warehouse himself.
for on a condition
for words < 600 {
One part instead of three. Other languages call this while; in Go it is the same for, just without the counter and the step.
for with no condition
for {
// until told to leave
}
It turns forever until a break is met inside. Servers and event loops are written this way.
break leaves the loop altogether. continue abandons the current turn and starts the next.
Picture it. A queue.
breakis leaving the queue for good.continueis giving up your turn and going straight to the next one without finishing what you came to do.
if with a short declaration
Here the last lesson comes back. A function hands back two values, and both are wanted only inside the test:
if minutes, ok := readingTime(700); ok {
fmt.Println(minutes)
}
The semicolon separates the declaration from the condition. minutes and ok live only inside this if and do not exist outside it — so they cannot get in the way or be confused with anything else. In Go this is how it is nearly always written when a result is wanted for exactly one test.
The fourth shape, later
for has one more form, range: it walks whatever is made of parts — a string letter by letter, a list item by item. We meet it on strings in the very next lesson, and on lists in the lesson on slices.
A function can call itself
A loop is not the only way to repeat. A function can call itself, and that is called recursion:
func countdown(n int) {
if n == 0 {
fmt.Println("go")
return
}
fmt.Println(n)
countdown(n - 1)
}
func main() {
countdown(3)
}
3
2
1
go
There are two parts here and both are compulsory. The first is the way out: if n == 0 and return, the case in which the function no longer calls itself. The second is the step that brings that case closer: countdown(n - 1), with a smaller number every time.
Take the way out away and the program will not stop. Go will not let it hang for ever, but it will not thank you either:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
Every call takes room in memory, and when the room runs out the program falls over. A for loop cannot fall over like this: it piles up no calls.
Picture it. A nesting doll. You open it, inside is the same doll a size smaller, and so on down to the smallest — which is solid. Were there no smallest one, you would be opening them for ever.
When it is chosen over a loop: when the data nests inside itself. A comment on a comment, a folder inside a folder, a reply to a reply — walking that with a loop is hard and with recursion natural. For a flat list a loop is simpler and faster, and in this course it is nearly always a loop.
The lesson map
Say it in your own words
Answer out loud or on paper without looking. The answers are at the end of the lesson.
- Why can the tests in
labelnot be reordered? - How does
breakdiffer fromcontinue? - Why write
if n, ok := f(); okwhennandokcould be declared on the line above?
Exercise
Required. Write a function label(views int) string: at 1000 or more it returns "popular", at 100 or more "being read", otherwise "new". Call it from main for 12, 340 and 1500 and print the results.
Optional.
- A counting loop from 1 to 10 that prints only the even numbers. Hint: the remainder of a division is
%, and even meansi%2 == 0. - Go back to the last lesson’s exercise that was waiting for an
if: makereadingTimereturn two values — the minutes, and aboolfor whether the word count is sensible. - A
forwith no condition that leaves on the fifth turn with abreak.
Where this goes in your blog
Branching is everywhere in a blog: show the article or answer 404, allow the edit or refuse it, print “no comments” or the list of them. And a loop is wanted the moment there is more than one article — in the lesson on slices you will walk all of them in a single line.
Answers
Show the answers
- Because the test that runs is the first one that fits, not the most exact one. A thousand views satisfies both
>= 100and>= 1000; with the hundred first, the thousand is never reached and “popular” never comes out. Conditions go from narrow to wide. breakends the loop entirely and execution carries on after it.continueends only the current turn: the rest of the body is skipped, but the loop goes on with the next value.- So that names do not outlive their use. Declared on the line above,
nandokstay to the end of the function, block those names for anything else, and suggest they can be used further down. Inside anifthey vanish at the closing brace.
Sources
If you have found a mistake or a typo in this article, tell us about it
Comments (0)
Log in to leave a comment →
No comments yet. Be the first.