Tony Bai · Go 语言第一课
Tony Bai
资深架构师,tonybai.com 博主
21492 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 59 讲
开篇词 (1讲)
结束语 (1讲)
Tony Bai · Go 语言第一课
15
15
1.0x
00:00/00:00
登录|注册

19|控制结构:Go的for循环,仅此一种

channel遍历
map遍历
字符串类型遍历
切片中的元素遍历
循环后置语句
循环体
条件判断表达式
循环前置语句
Go语言中的等价形式
C语言中的for语句
其他方案实现预期输出
遍历map中元素的随机性
range表达式的副本
循环变量的重用
带label的应用
彻底跳出循环
中断当前循环体
嵌套循环中的应用
继续下一次迭代
中断当前迭代
for range循环形式
无限循环
可选部分的省略
多循环变量
组成部分
经典使用形式
Go语言仅有for语句
主流编程语言提供支持
重复执行同一段代码
switch-case语句
if语句
程序控制结构
思考题
for语句的常见“坑”与避坑方法
break语句的使用
带label的continue语句
for语句
循环结构
上一节课
控制结构:Go的for循环,仅此一种

该思维导图由 AI 生成,仅供参考

你好,我是 Tony Bai。
上一节课,我们开始了对程序控制结构的学习,学习了分支结构中的 if 语句。上节课我们也说过,针对程序的分支结构,Go 提供了 if 和 switch-case 两种语句形式。那你肯定在想,这节课肯定是要讲 switch-case 语句了吧!我不想按常规出牌,这一节课我们换换口味,挑战一下程序控制结构中最复杂的一款:循环结构。
为什么这么设置呢?因为我想让你能更早开始动手编写具有循环结构的 Go 代码。虽然 switch-case 分支结构也非常重要,但毕竟我们已经有了 if 分支语句的基础了,很多时候用 if 也可以替代 switch-case,所以把它往后放放也没关系。
日常编码过程中,我们常常需要重复执行同一段代码,这时我们就需要循环结构来帮助我们控制程序的执行顺序。一个循环结构会执行循环体中的代码直到结尾,然后回到开头继续执行。 主流编程语言都提供了对循环结构的支持,绝大多数主流语言,包括 C 语言、C++、Java 和 Rust,甚至连动态语言 Python 还提供了不止一种的循环语句,但 Go 却只有一种,也就是 for 语句。
所以这节课,我们就来系统学习一下 Go 语言循环结构中的这一支独苗,for 语句,聚焦于它的使用形式和常见坑点,让你能更快上手 Go 编码。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Go语言中for循环的多种形式及其灵活应用是本文的主要内容。文章首先介绍了经典for循环形式,详细解释了循环前置语句、条件判断表达式、循环体和循环后置语句的执行顺序和作用。其次,讲解了使用多循环变量的复杂例子,并指出循环前置和后置语句都是可选的。此外,介绍了for循环的另外两种形式:仅保留循环判断条件表达式和无限循环形式。最后,详细介绍了for range形式的应用,以及带label的continue语句和break语句的使用方法,以及它们在嵌套循环中的应用。文章还提到了与for语句相关的常见“坑”点,主要集中在for range这个“语法糖”上。通过对这些内容的解释,读者能够全面了解并掌握Go语言中for循环的使用方法,同时也提醒读者在使用for range时需要注意避免常见的“坑”点。文章内容涵盖了for循环的各种形式和应用场景,为读者提供了全面的学习和使用指南。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Tony Bai · Go 语言第一课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(34)

  • 最新
  • 精选
  • 布凡
    老师,最后问题三:遍历 map 中元素的随机性中举的例子没看懂: 1、示例1中,当 k="tony"作为第一个迭代的元素时,我们将得到如下结果:包含了“tony”,是因为for循环中读取的是“tony”不允许被删除吗? 2、示例2中,是当m["lucky"]=24 这个值被其它原map中的值覆盖,导致赋值不成功吗? 还请老师指教

    作者回复: 1. 不是啊。之所以还能输出tony,是因为k, v从map中获取值的操作发生在delete之前啊。如果k="tony"作为第一个迭代的元素时,我们用k,v从map中取出了tony, 21。然后delete掉tony,此时k, v的值已经是tony, 21了,输出就正常了。如果tony不是第一个迭代元素,那么已经被删除掉了,后续迭代就不会输出它了。 2. 不是被覆盖了。对map迭代的实质是按顺序逐个bucket的遍历,每个bucket也是逐个遍历其中的key。如果luckey创建与第一个被遍历的元素之前了,那么后续就不会遍历它了。别忘了,key存储在哪里是根据hash值来定的。

    2021-11-24
    42
  • 用0和1改变自己
    用数组指针替换数组 func main() { var a = [5]int{1, 2, 3, 4, 5} var r [5]int fmt.Println("original a =", a) for i, v := range &a { //a 改为&a if i == 0 { a[1] = 12 a[2] = 13 } r[i] = v } fmt.Println("after for range loop, r =", r) fmt.Println("after for range loop, a =", a) }

    作者回复: 正确✅

    2021-11-24
    3
    37
  • lesserror
    Tony Bai老师,你在评论中说:“如果luckey创建与第一个被遍历的元素之前了,那么后续就不会遍历它了。别忘了,key存储在哪里是根据hash值来定的”。 这个我还是似懂非懂,能举例说明一下么? 非常感谢。

    作者回复: map的遍历顺序有随机性。但这种随机仅仅是在创建初始iterator时随机选择一个bucket。假设按bucket2->bucket3->...顺序迭代,假设已经遍历完bucket2,正在遍历bucket3,此时插入lucy这个key,恰插到bucket2中,由于之前已经遍历完bucket2,后续的遍历不会再重复遍历bucket2,于是lucy便无法出现在后续遍历路径上。如果lucy插入到bucket3后面的bucket中,则会出现在遍历路径上,我们就能看到这个key。

    2021-12-01
    5
    16
  • 罗杰
    map 中的坑比想象的要多,使用的时候一定要细心。老师基本上把能遇到的坑都指出来了。惭愧的是 continue 和 break 的 label 从来没用过。

    作者回复: 看来你日常写的业务逻辑还不够复杂。居然没有嵌套循环:)

    2021-11-24
    3
    8
  • crabxyj
    问题三:java 中是不允许在遍历中修改当前集合的,和fastfail有关,直接会抛出异常,而go允许,但遍历结果不可控

    作者回复: 👍

    2022-02-16
    2
    7
  • 对于 map 遍历的那个例子,新增一个 map key m["lucy"] = 24 , 这里的结果counter 不应该一直是 4吗? 给 map 添加的元素为什么有的时候可以访问到 有的时候访问不到?

    作者回复: 是否访问到,视m["lucy"]=24这个键值对的插入位置而定。

    2021-11-25
    4
    4
  • 酥宝话不多
    传数组地址,&a

    作者回复: ✅

    2021-11-24
    3
  • 白小白
    老师,请教一下:最后一个例子的结果出现的原因正是因为map 中元素的随机性,如何能保证只输出一种结果?

    作者回复: 有随机性,无法保证输出哪种结果。

    2022-08-08归属地:辽宁
    2
  • William Ning
    老师同学好, 关于评论列表中第一条 中的 第二个问题,就是map新元素的插入,位置是随机的,不定的,所以,可能插入到原来第一个元素的前面,也可能在后面,如果在前面,就被跳过了,便没有输出。 从个人代码执行,输出结果便可知,m["lucy"] = 24 插入的位置,确实会出现在任意的位置,因为输出的位置,从0-3都有~ 但是关于上面的回答中的“,别忘了,key存储在哪里是根据hash值来定的” 如果是这样,m["lucy"] = 24,lucy应该是一个确定的值,不论经过次重复的hash,hash值应该都是一样的,也就是说,插入的位置,应该都是确定的,那么输出结果应该只有上面结果的中的一种可能,我的理解出了什么偏差吗? 谢谢老师,同学~ 下面是输出结果,供参考 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 counter is 3 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tom 22 jim 23 lucy 24 tony 21 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tom 22 jim 23 lucy 24 tony 21 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tony 21 tom 22 jim 23 lucy 24 counter is 4 ➜ golearning go run . tom 22 jim 23 lucy 24 tony 21 counter is 4 ➜ golearning go run . jim 23 lucy 24 tony 21 tom 22 counter is 4 ➜ golearning go run . tom 22 jim 23 lucy 24 tony 21 counter is 4 ➜ golearning go run . jim 23 lucy 24 tony 21 tom 22 counter is 4

    作者回复: 虽然插入的位置可能是固定的,但遍历的起点是随机的。看看你的程序输出的的结果 是不是按tony , tom , jim, lucy组成了一个环。

    2022-03-17
    2
    2
  • pyhhou
    关于思考题,除了换成切片或者指针外,我们可以将 for range 替换为传统的 for ;; 循环就可以解决问题。 这里有一个衍生的问题,还烦请老师解答,如果说 for range 会对遍历的结构产生副本,那么我们用 for range 去遍历大型的数组的话是不是会有性能或者资源浪费等问题?所以说在平时,我们还是尽量用传统的三段式 for 循环而不是 for range?这样即使是不太了解 go 的人来看代码也不会有困惑

    作者回复: 好问题!我是这么想的: 第一尽量用切片代替纯数组loop吧,这样可以获得稳定且一致的性能。 第二,即便纯数组loop,for range也不一定比经典for loop性能差,go语言对for range做了特殊优化。不过也要看for range的数组的元素类型,如果是包含一定数量字段的结构体类型,目前优化还不到位。

    2022-03-10
    2
收起评论
显示
设置
留言
34
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部