Control Structures¶
If Statements¶
If-statements in Go are similar to those in C-like languages. For example:
package main // every Go program must start with a package declaration
import "fmt" // print functions and Scanf are in the fmt package
func main() {
fmt.Print("Please enter your score (0 to 100): ")
var score float64 // score is a 64-bit floating point number
// initialized to 0.0
_, ok := fmt.Scanf("%f", &score) // _ is the blank identifier,
// and it is used here to discard the
// first value (the number of items
// scanned) returned by Scanf
if ok != nil {
panic("input error")
}
fmt.Printf("Your score: %.1f\n", score)
if score < 0 {
fmt.Println("Negative scores are not allowed.")
} else if score < 50 {
fmt.Println("Sorry, you failed.")
} else if score < 100 {
fmt.Println("Congratulations, you passed.")
} else if score == 100 {
fmt.Println("Perfect! You passed.")
} else {
fmt.Println("Scores over 100 are not allowed.")
}
}
Notice that you don’t need to put the if-conditions inside ()
-brackets.
Also, you must always use curly braces for the body of an if-statment, even when it contains a single statement. For example, this causes a compiler error:
if ok != nil // compiler error: missing braces
panic("input error")
You must instead write this:
if ok != nil {
panic("input error")
}
Switch Statements¶
The Go switch
statements come in two main varieties. The first kind is
just an alternative syntax for if-else-if structures. For example:
switch { // notice that there is no variable here
case score < 0:
fmt.Println("Negative scores are not allowed.")
case score < 50:
fmt.Println("Sorry, you failed.")
case score < 100:
fmt.Println("Congratulations, you passed.")
case score == 100:
fmt.Println("Perfect! You passed.")
default:
fmt.Println("Scores over 100 are not allowed.")
}
Notice that no “break” statements are needed. In a C-style switch statement,
we’d have to put break
after each case body to avoid “fall-through”. But
in Go the default is not to fall-through a switch statement, which is
almost always what is wanted. If for some reason you do want fall-through
behaviour, add the statement fallthrough
as the last statement of case
body to make the flow of control automatically go to the next case.
The second style of Go switch statements takes a variable and switches on its value. For example, here is a switch on a string:
// ... grade is a previously assigned string variable ...
switch grade {
case "A+", "A", "A-":
fmt.Println("excellent")
case "B+", "B", "B-":
fmt.Println("good")
case "C+", "C", "C-":
fmt.Println("average")
case "D":
fmt.Println("below average")
case "F":
fmt.Println("failure")
default:
panic("unknown grade \"" + grade + "\"")
}
Note that grade
is a string
variable, and so this shows that Go can
switch on strings (as well as numbers and characters).
Also note the use of panic
in the default
clause. panic
is a
built-in Go function that, when called, intentionally crashes the program. It
should be used in cases where a serious unrecoverable problems occurs.
C-like For Loops¶
Go has only one named loop: for
. It is flexible enough to simulate both
C-style while-loops and for-loops, plus range-style loops.
Here’s a traditional C-style for loop that sums the squares of the numbers from 1 to 100:
var sum int
for i := 0; i < 100; i++ {
sum += (i + 1) * (i + 1)
}
fmt.Printf("sum: %d\n", sum)
Notice there are no ()
-brackets required around the statements after
for
.
As with if-statements, the curly braces are always required:
for i := 1; i <= 100; i++ // compiler error: missing braces
sum += i * i
C-like While Loops¶
Go can simulate C-style while-loops by leaving out the initialization and increment statements of a for-loop:
i := 1
for i <= 100 {
sum += i * i
i++
}
If you want an infinite loop, you can write this:
for {
fmt.Println("and again and again ...")
}
Ranged Loops¶
Finally, ranged for-loops iterate through a collection. For example:
s := "apple"
for i, c := range s { // := used so that i and c are created
fmt.Printf("%d, %c\n", i, c)
}
This prints:
0, a
1, p
2, p
3, l
4, e
This style of loop also works with arrays, slices, and maps. In many cases, ranged loops are the preferred kind of loop because they handle the details of accessing all the elements of a collection.
Sometimes you might just want the values of the collection, and have no need for the index, e.g.:
s := "apple"
for i, c := range s { // compiler error: i is not used!
fmt.Printf("%c\n", c)
}
Unfortunately, this doesn’t compile because i
is not used and Go doesn’t
permit unused variables. The solution is to use the blank identifier _
in place of i
:
s := "apple"
for _, c := range s { // _ used instead of i
fmt.Printf("%c\n", c)
}
This compiles and runs as expected.
Questions¶
Give two examples of how the Go
switch
statement is more general than the traditionalswitch
statement in C/C++.What is the blank identifier? Why is it useful?
What happens when you try to compile and run this code fragment?
// assume fmt has been imported x := 6 if x > 5 fmt.Println("x is ") fmt.Println("greater ") fmt.Println("done")
Write a loop that prints the numbers from 10 down to 1. Do it in Go using a C-like:
- for-loop
- while-loop
Write a Go ranged loop that prints just the characters of a string
s
in reverse order. For example, ifs
is"apple"
, the loop should print:e l p p a
Go does not have a do-while loop, i.e. a loop whose condition is checked at the end of the loop body instead of the beginning. Is this a good feature or bad feature of Go? Justify your answer.