兄弟们,姐妹们,代码狗们!今天咱们来聊点Go语言里那个你天天用,却可能从未真正懂它的家伙——循环语句!
别跟我说什么“循环不就是重复执行代码嘛”,要是这么想,那你可太小看Go的循环了!在Go的世界里,循环只有一位大哥叫for,但这位大哥却有三副面孔,能扮演其他语言里for、while、foreach所有的角色!
基础for循环:直男式表白
先来看看最基础的for循环,这哥们儿长得特别直白:
for 初始化语句; 条件表达式; 后续操作 {
// 循环体
}
来个实际例子,假设你要打印0到4:
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Printf("当前是第%d次循环\n", i)
}
}
运行结果:
当前是第0次循环
当前是第1次循环
当前是第2次循环
当前是第3次循环
当前是第4次循环
看见没?Go的for循环不需要小括号!这是跟其他语言的一大区别。忘了去掉括号?编译器分分钟教你做人!
但这里有个小细节:变量i的作用域只在循环内部。出了这个循环,i就跟你前任一样——不存在了!
第二副面孔:while循环的替身
我知道你在想什么:“Go里有没有while循环?” 答案是:没有专门的while关键字,但for能完美cosplay!
Go里的while风格循环长这样:
for 条件表达式 {
// 循环体
}
来个实际场景:假设你在写游戏,玩家血量大于0就继续游戏:
package main
import "fmt"
func main() {
hp := 10
for hp > 0 {
fmt.Printf("玩家还在战斗,剩余血量:%d\n", hp)
hp-- // 每次循环血量减1
}
fmt.Println("游戏结束!")
}
运行结果:
玩家还在战斗,剩余血量:10
玩家还在战斗,剩余血量:9
...
玩家还在战斗,剩余血量:1
游戏结束!
这种循环在你不知道具体要循环多少次,只知道循环条件时特别有用!
无限循环:代码界的鬼打墙
有时候你需要一个永远执行的循环,比如服务器的主循环:
for {
// 这个循环会一直执行,直到遇见break或return
}
但小心!这玩意要是没设置退出条件,就真成鬼打墙了:
package main
import (
"fmt"
"time"
)
func main() {
count := 0
for {
fmt.Printf("我已经循环了%d次...\n", count)
count++
time.Sleep(1 * time.Second) // 每秒一次
if count >= 5 {
fmt.Println("够了够了,停!")
break // break是跳出循环的关键!
}
}
}
运行结果:
我已经循环了0次...
我已经循环了1次...
我已经循环了2次...
我已经循环了3次...
我已经循环了4次...
够了够了,停!
第三副面孔:foreach的优雅化身
在其他语言里遍历数组、切片时常用foreach,Go里用for range:
for 索引, 值 := range 集合 {
// 循环体
}
实战一下,遍历一个切片:
package main
import "fmt"
func main() {
fruits := []string{"苹果", "香蕉", "橙子", "草莓"}
for index, fruit := range fruits {
fmt.Printf("第%d个水果是:%s\n", index, fruit)
}
}
运行结果:
第0个水果是:苹果
第1个水果是:香蕉
第2个水果是:橙子
第3个水果是:草莓
如果你不需要索引,用下划线_忽略:
for _, fruit := range fruits {
fmt.Printf("我喜欢吃:%s\n", fruit)
}
循环控制:break和continue的骚操作
break:立即结束整个循环,就像上课时突然火警响了,大家都得离开教室。
continue:跳过本次循环剩余代码,直接进入下一次循环,就像上课时你尿急去厕所,回来继续听课。
来看个复杂点的例子:
package main
import "fmt"
func main() {
fmt.Println("找出0-9之间的所有奇数:")
for i := 0; i < 10; i++ {
if i%2 == 0 { // 如果是偶数
continue // 跳过这次循环
}
fmt.Printf("%d是奇数!\n", i)
if i == 7 {
fmt.Println("遇到7就提前结束!")
break
}
}
}
运行结果:
找出0-9之间的所有奇数!
1是奇数!
3是奇数!
5是奇数!
7是奇数!
遇到7就提前结束!
标签循环:高级玩家的传送门
这是Go循环里最骚的功能之一——带标签的break和continue!让你能从多层循环中直接跳转到指定位置。
package main
import "fmt"
func main() {
fmt.Println("标签循环演示:")
// 外层循环标签
OuterLoop:
for i := 0; i < 3; i++ {
fmt.Printf("外层循环i=%d\n", i)
for j := 0; j < 3; j++ {
fmt.Printf(" 内层循环j=%d\n", j)
if i == 1 && j == 1 {
fmt.Println("触发条件,跳出到外层循环!")
continue OuterLoop // 直接继续外层循环的下一次
}
}
}
}
运行结果:
外层循环i=0
内层循环j=0
内层循环j=1
内层循环j=2
外层循环i=1
内层循环j=0
内层循环j=1
触发条件,跳出到外层循环!
外层循环i=2
内层循环j=0
内层循环j=1
内层循环j=2
实战案例:摸鱼时刻表
来点实际的!假设你要做个工作日摸鱼提醒:
package main
import (
"fmt"
"time"
)
func main() {
workTasks := []string{"写代码", "开会", "写文档", "调试bug", "代码review"}
breakTimes := []int{2, 4} // 在第2和第4个任务后摸鱼
fmt.Println("=== 工作日摸鱼时刻表 ===")
taskCount := 0
for taskCount < len(workTasks) {
fmt.Printf("当前任务:%s\n", workTasks[taskCount])
// 检查是不是摸鱼时间
for _, breakTime := range breakTimes {
if taskCount == breakTime {
fmt.Println(" -> 摸鱼时间到!刷会儿微博...")
time.Sleep(1 * time.Second) // 模拟摸鱼1秒
}
}
taskCount++
// 防止无限循环的保险
if taskCount > 10 {
fmt.Println("警告:任务太多,摸鱼失败!")
break
}
}
fmt.Println("下班啦!")
}
性能小贴士
- 预分配切片容量:在循环前用
make([]T, 0, capacity)预分配,避免循环中反复扩容 - 避免在循环内创建大对象:大的内存分配放到循环外面
- range返回的是副本:修改元素要用索引方式
// 错误示范
for _, value := range slice {
value = newValue // 这不会修改原切片!
}
// 正确做法
for i := range slice {
slice[i] = newValue // 这样才会修改原切片
}
常见坑点总结
- 忘记break导致无限循环
- 在循环外使用循环变量
- 修改range迭代的副本以为修改了原值
- 并发访问共享数据没加锁
结语
Go的循环看似简单,实则内涵丰富!从基础的for循环到灵活的while替代,再到优雅的range遍历,每一招都用好了都能让你的代码更简洁高效。
记住,好的循环代码应该像好笑话一样——不需要解释就能看懂。多用有意义的变量名,保持循环简短,适当使用break和continue,你的代码质量立马提升一个level!
现在,去写点漂亮的循环代码吧!如果还有疑问,记住Go箴言:少即是多,简单就是美!
本文示例代码在Go 1.19+测试通过,摸鱼建议根据实际工作情况酌情使用,被老板抓到时别说是跟我学的!

被折叠的 条评论
为什么被折叠?



