Go's One Loop to Rule Them All: for, range, break, and the goto You Shouldn't Use
The Divine Art of the North Sea (The Supreme Mystery Classic)
package main
import "fmt"
type Person struct {
Name string
Age int
Sex string
}
func main() {
person := Person{
Name: "张三",
Age: 18,
Sex: "男",
}
if person.Age >= 18 {
fmt.Println("成年")
} else {
fmt.Println("未成年")
}
}
We defined a Person struct containing three fields: Name, Age, and Sex. Then we created an instance and checked whether its age is 18 or older: if 18 or older, output "成年" (adult); otherwise, output "未成年" (minor). This is the most basic if / else two-way branch.
Multi-Condition Branching
package main
import "fmt"
type Person struct {
Status string
}
func main() {
person := Person{
Status: "在线",
}
if person.Status == "在线" {
fmt.Println("在线")
} else if person.Status == "离线" {
fmt.Println("离线")
} else if person.Status == "忙碌" {
fmt.Println("忙碌")
} else {
fmt.Println("未知状态")
}
}
When you need to handle three or more branches, you can chain else if after if. Conditions are evaluated top to bottom, and execution stops as soon as the first true branch is hit. The final else acts as a catch-all for any unmatched cases.
The example above simulates a user's online status: when Status is "在线" (online), "离线" (offline), or "忙碌" (busy), it prints the corresponding text; any other value prints "未知状态" (unknown status).
The same logic is more concise with switch — place the value to be checked after switch, and each case corresponds to a possible value:
package main
import "fmt"
type Person struct {
Status string
}
func main() {
person := Person{
Status: "在线",
}
switch person.Status {
case "在线":
fmt.Println("在线")
case "离线":
fmt.Println("离线")
case "忙碌":
fmt.Println("忙碌")
default:
fmt.Println("未知状态")
}
}
switch compares person.Status against each case in turn and executes the matching branch. Go's switch does not fall through to the next case by default (no break needed). If no case matches, the default branch runs.
| Syntax | Use Case |
|---|---|
if / else if |
Conditions differ and are hard to extract into a single expression |
switch expression |
Matching a single value against multiple fixed possibilities (e.g., status, grade, day of the week) |
Nested Logic
package main
import "fmt"
type Person struct {
Name string
Age int
Sex string
}
func main() {
person := Person{
Name: "张三",
Age: 18,
Sex: "男",
}
if person.Age >= 18 {
if person.Sex == "男" {
fmt.Println("成年男性")
} else {
fmt.Println("成年女性")
}
} else {
fmt.Println("未成年")
if person.Sex == "男" {
fmt.Println("未成年男性")
} else {
fmt.Println("未成年女性")
}
}
}
Multiple if conditions can be nested. We first check whether age is 18 or older; if so, we then check whether sex equals "男" (male). If it does, output "成年男性" (adult male); otherwise, output "成年女性" (adult female). If not 18 or older, output "未成年" (minor), then check sex again: if male, output "未成年男性" (minor male); otherwise, output "未成年女性" (minor female). This is basic logical nesting. You can nest more than two levels deep, but you must pay attention to logical correctness.
Logical Operators
Conditions often need to combine multiple expressions. The common logical operators are:
| Operator | Meaning | Example | True When |
|---|---|---|---|
&& |
AND | a && b |
Both a and b are true |
|| |
OR | a || b |
At least one of a or b is true |
! |
NOT | !a |
a is false |
AND (&&)
age := 18
sex := "男"
if age >= 18 && sex == "男" {
fmt.Println("成年男性")
}
&& means AND: the entire expression is true only if both the left and right conditions are true. Above, "成年男性" (adult male) is printed only when "age 18 or older" AND "sex is male".
OR (||)
age := 33
if age == 18 || age == 19 {
fmt.Println("18 岁或 19 岁")
} else {
fmt.Println("其他年龄")
}
|| means OR: the entire expression is true if at least one of the left or right conditions is true. Above, the if branch runs when age is 18 or 19; otherwise, the else branch runs.
NOT (!)
isLogin := false
if !isLogin {
fmt.Println("请先登录")
}
! inverts a boolean value: !true is false, !false is true. It's often used for branching when a condition is not met.
Exercises
- Basic Branching: Declare an
intvariable for a score. Useif/else if/elseto determine the grade: 90 and above is "优秀" (excellent), 60–89 is "及格" (pass), below 60 is "不及格" (fail), and print the result. - switch Practice: Define a
stringvariable representing a day of the week (e.g.,"周一"). Useswitchto match and print a corresponding message; if no match, go todefaultand output "无效的星期" (invalid day of the week). - Status Check: Referring to the
Personstruct in the text, setStatusto "在线" (online), "离线" (offline), "忙碌" (busy), and a custom value. Run both theif/else ifandswitchversions separately and observe whether the output is consistent. - Logical Operators: Declare two variables,
ageandhasTicket. Use&&to check "age 18 or older AND has a ticket" for entry permission. Then use||to check "is a member OR age over 60" for a discount. Print the results for each. - Comprehensive Exercise: Define a struct containing
Name,Age, andScore. Combine with nestedifchecks: output "合格" (qualified) only if age is 18 or older AND score is 60 or above; otherwise, output "不合格" (unqualified), and include the name in the output.
The Cycle of Rebirth
Go has only one looping keyword: for. There is no while and no do-while; all loop forms are expressed through for.
Standard for Loop
We declared a slice and traversed it using the classic "init; condition; post" syntax:
package main
import "fmt"
func main() {
var hobbys = []string{"吃饭", "睡觉", "打豆豆"}
for i := 0; i < len(hobbys); i++ {
fmt.Println(hobbys[i])
}
}
The for statement is followed by three sections separated by semicolons:
| Part | Purpose | Example Above |
|---|---|---|
| Init | Executed once before the loop starts | i := 0 |
| Condition | Checked before each iteration; loop continues if true | i < len(hobbys) |
| Post | Executed after each loop body finishes | i++ |
The output is, in order: 吃饭, 睡觉, 打豆豆.
All three sections can be omitted. Leaving only the condition is equivalent to while in other languages:
package main
import "fmt"
func main() {
i := 0
for i < 3 {
fmt.Println(i)
i++
}
}
Omitting the condition as well creates an infinite loop, which requires a break to exit:
package main
import "fmt"
func main() {
i := 0
for {
fmt.Println(i)
i++
if i >= 3 {
break
}
}
}
range Loop
When iterating over slices, arrays, strings, maps, and channels, range is more concise:
package main
import "fmt"
func main() {
var hobbys = []string{"吃饭", "睡觉", "打豆豆"}
for index, hobby := range hobbys {
fmt.Println(index, hobby)
}
}
Each iteration of range returns two values:
- The first is the index (or the key for a map)
- The second is the corresponding element value
The output is:
0 吃饭
1 睡觉
2 打豆豆
If you only need the value and not the index, use _ to discard the first return value:
for _, hobby := range hobbys {
fmt.Println(hobby)
}
If you only need the index and not the value, just write one variable:
for index := range hobbys {
fmt.Println(index)
}
Iterating Over a Map
package main
import "fmt"
func main() {
person := map[string]string{
"name": "张三",
"city": "杭州",
}
for key, value := range person {
fmt.Println(key, value)
}
}
Note: the iteration order of a map is not fixed; the printed order may differ each time the program runs.
Iterating Over a String
package main
import "fmt"
func main() {
text := "你好Go"
for index, char := range text {
fmt.Printf("下标 %d,字符 %c\n", index, char)
}
}
When using range to iterate over a string, you get Unicode code points (runes), not individual bytes. Characters like "你" and "好" each occupy 3 bytes, so the index will jump according to byte positions.
| Syntax | Use Case |
|---|---|
for i := 0; i < len(x); i++ |
When you need precise control over the index, step size, or to start from the middle/iterate in reverse |
for i, v := range x |
Sequential iteration over slices, arrays, strings, maps |
break and continue
Loops often need to "exit early" or "skip an iteration":
| Keyword | Meaning |
|---|---|
break |
Immediately exits the current loop |
continue |
Skips the remaining code for this iteration and proceeds to the next iteration |
break: Exiting a Loop
package main
import "fmt"
func main() {
hobbys := []string{"吃饭", "睡觉", "打豆豆"}
for _, hobby := range hobbys {
if hobby == "睡觉" {
break
}
fmt.Println(hobby)
}
}
When "睡觉" is encountered, break is triggered, and subsequent elements are not traversed. The output is only: 吃饭.
continue: Skipping an Iteration
package main
import "fmt"
func main() {
hobbys := []string{"吃饭", "睡觉", "打豆豆"}
for _, hobby := range hobbys {
if hobby == "睡觉" {
continue
}
fmt.Println(hobby)
}
}
When "睡觉" is encountered, continue skips the print statement, but the loop continues. The output is: 吃饭, 打豆豆.
Labeled break
In nested loops, a plain break only exits the innermost loop. To break out of an outer loop at once, you can add a label to the loop:
package main
import "fmt"
func main() {
Outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break Outer
}
fmt.Println(i, j)
}
}
}
break Outer directly exits the loop labeled Outer. continue can also be used with a label, meaning to jump to the next iteration of the specified loop.
goto
goto can jump to a labeled position within the same function. It works, but readability tends to suffer; break / continue / return are preferred in everyday code.
package main
import "fmt"
func main() {
i := 0
Loop:
fmt.Println(i)
i++
if i < 3 {
goto Loop
}
}
The above uses goto to simulate a simple loop, printing 0, 1, 2. In real projects, avoid it unless for specific scenarios like error cleanup.
Exercises
- Standard for: Write a loop from
1to10and print all even numbers. - range Practice: Define a slice
[]string{"春", "夏", "秋", "冬"}. Print it using three differentrangeforms: "index only", "value only", and "index and value". - break / continue: Iterate from
1to20. Usecontinueto skip numbers divisible by3. Usebreakto stop the loop as soon as a number greater than15is encountered. Observe which numbers are ultimately printed. - while-like: Use a "condition-only"
forloop (no init or post sections) to calculate the sum1 + 2 + ... + 100and print the result. - Comprehensive Exercise: Define a
map[string]intrepresenting scores for various subjects (e.g., Chinese, Math, English). Userangeto iterate: for subjects with a score below 60, print "不及格" (fail); for the rest, print "及格" (pass). Also count the number of passing subjects.
Top 1 from juejin.cn, machine-translated. The original thread is authoritative.
Update please [pleading]