GO语言控制流程示例
一、条件判断:if-else语句(深度解析)
1.1 基础结构与短声明
Go的if
语句允许在条件中直接声明变量,这是其他语言不具备的特性。
语法:
if 变量, 错误 := 函数调用(); 条件表达式 {
// 执行代码
}
示例:文件读取时的安全判断
package main
import (
"fmt"
"os"
)
func main() {
if data, err := os.ReadFile("test.txt"); err == nil {
fmt.Println("文件内容:", string(data))
} else {
fmt.Println("读取失败:", err)
}
}
运行结果:
文件内容: Hello World!(当文件存在时)
或
读取失败: open test.txt: no such file or directory
关键点:
- 变量作用域仅限当前
if
块 - 错误处理的最佳实践
1.2 嵌套条件与逻辑运算符
Go支持&&
(与)、||
(或)、!
(非)三种逻辑运算符
实战案例:用户权限验证系统
package main
func main() {
var (
age = 25
isVIP = true
balance = 1500
)
if age >= 18 && (isVIP || balance >= 1000) {
fmt.Println("权限通过")
} else {
fmt.Println("权限不足")
}
}
运行结果:
权限通过(当前条件满足)
二、循环语句:for(全场景解析)
2.1 类C风格循环
语法结构:
for 初始化; 条件; 迭代 {
// 循环体
}
进阶示例:素数生成器
package main
import "fmt"
func main() {
primes := make([]int, 0)
for num := 2; len(primes) < 10; num++ {
isPrime := true
for i := 2; i <= num/2; i++ {
if num%i == 0 {
isPrime = false
break
}
}
if isPrime {
primes = append(primes, num)
}
}
fmt.Println("前10个素数:", primes)
}
运行结果:
前10个素数:
关键技巧:
- 嵌套循环的应用
- 素数判断算法优化
2.2 无限循环与通道通信
结合for{}
和goroutine实现生产者-消费者模型
示例:并发日志处理系统
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var (
logs = make(chan string, 100)
wg sync.WaitGroup
)
// 生产者
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 5; i++ {
logs <- fmt.Sprintf("日志消息 %d", i)
time.Sleep(time.Second)
}
close(logs)
}()
// 消费者
wg.Add(1)
go func() {
defer wg.Done()
for log := range logs {
fmt.Println("处理:", log)
}
}()
wg.Wait()
}
运行结果:
处理: 日志消息 0
处理: 日志消息 1
处理: 日志消息 2
处理: 日志消息 3
处理: 日志消息 4
核心技术:
- 通道(channel)的使用
- goroutine并发控制
2.3 for-range的深度应用
2.3.1 字符串遍历
package main
import "fmt"
func main() {
s := "中English"
for i, r := range s {
fmt.Printf("索引%d: %c\n", i, r)
}
}
运行结果:
索引0: 中
索引3: E
索引4: n
...
注意:中文字符占用3个字节,因此索引不连续
2.3.2 Map遍历优化
package main
import (
"fmt"
"sort"
)
func main() {
scores := map[string]int{
"Alice": 95,
"Bob": 88,
"Charlie": 76,
}
var keys []string
for k := range scores {
keys = append(keys, k)
}
sort.Strings(keys) // 按键排序
for _, k := range keys {
fmt.Printf("%s: %d\n", k, scores[k])
}
}
运行结果:
Alice: 95
Bob: 88
Charlie: 76
技巧:通过临时切片实现有序遍历
三、流程控制:break/continue/fallthrough
3.1 多层循环跳出
使用带标签的break
跳出多层循环
示例:二维数组查找
package main
import "fmt"
func main() {
matrix := int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
search := 5
外包:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if matrix[i][j] == search {
fmt.Printf("找到在位置%d-%d\n", i, j)
break 外包 // 直接跳出外层循环
}
}
}
}
运行结果:
找到在位置1-1
3.2 continue的深度应用
示例:过滤敏感词
package main
import "fmt"
func main() {
text := "今天天气真好,我们去公园吧!"
sensitive := map[rune]bool{'好': true, '园': true}
var filtered string
for _, r := range text {
if sensitive[r] {
continue // 跳过敏感字符
}
filtered += string(r)
}
fmt.Println(filtered)
}
运行结果:
今天天气,我们去吧!
3.3 fallthrough的危险用法
示例:多条件匹配陷阱
package main
import "fmt"
func main() {
num := 5
switch {
case num < 0:
fmt.Println("负数")
case num < 10:
fmt.Println("个位数")
fallthrough // 错误!会导致后续条件被跳过
case num < 100:
fmt.Println("两位数")
default:
fmt.Println("其他")
}
}
运行结果:
个位数
两位数
警告:使用fallthrough时需特别注意条件顺序
四、实战项目:简易计算器
结合所有控制语句开发交互式计算器
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
func main() {
for {
fmt.Print("请输入表达式(输入q退出): ")
var input string
fmt.Scanln(&input)
if strings lower(input) == "q" {
fmt.Println("退出程序")
os.Exit(0)
}
parts := strings.Split(input, " ")
if len(parts) != 3 {
fmt.Println("格式错误:应为 数字 运算符 数字")
continue
}
num1, err1 := strconv.Atoi(parts)
num2, err2 := strconv.Atoi(parts)
if err1 != nil || err2 != nil {
fmt.Println("请输入有效数字")
continue
}
var result int
switch parts {
case "+":
result = num1 + num2
case "-":
result = num1 - num2
case "*":
result = num1 * num2
case "/":
if num2 == 0 {
fmt.Println("除数不能为0")
continue
}
result = num1 / num2
default:
fmt.Println("不支持的运算符")
continue
}
fmt.Printf("%s = %d\n", input, result)
}
}
运行示例:
请输入表达式(输入q退出): 5 + 3
5 + 3 = 8
请输入表达式(输入q退出): 10 / 0
除数不能为0
请输入表达式(输入q退出): q
退出程序
包含技术点:
- 无限循环
- 条件判断
- 错误处理
- 字符串操作
- 带标签的break
五、常见错误与调试技巧
- 循环变量作用域问题
for i := 0; i < 5; i++ {
go func() {
fmt.Println(i)
}()
}
错误结果:输出5个5
修复方案:
for i := 0; i < 5; i++ {
go func(j int) {
fmt.Println(j)
}(i)
}
- for-range遍历Map时的并发安全
m := map[int]string{1:"a", 2:"b"}
go func() {
delete(m, 1)
}()
for k := range m {
fmt.Println(k)
}
解决方案:先复制键到切片再遍历
六、性能优化建议
- 循环展开:对简单循环进行手动展开
- 避免重复计算:将循环内不变的计算移到外部
- 使用通道代替互斥锁:在并发场景中优先使用goroutine+channel
分享一张图片,未来加油!!