Golang语言流程控制之for循环结构篇

简介: 这篇文章详细介绍了Golang语言中的for循环结构,包括for循环的基本写法、引入、原理、死循环案例,for range键值循环的使用,以及break、continue、goto和return关键字在循环控制中的运用,并提供了练习题来加深理解。

                                              作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。

一. for循环

1 for循环基本写法

Go语言中的所有循环类型均可以使用for关键字来完成,换句话说,Go语言并不支持"while","do...while"类似的写法。

for循环的基本格式如下:
    for 初始表达式;布尔表达式;迭代因子{
        循环体语句
    }

for循环语句是支持迭代的一种通用结构,是最有效,最灵活的循环结构。

for循环在第一次反复之前要进行初始化,即初始化表达式,随后,对布尔表达式进行判定,若判定结果为true,则执行循环体,否则,终止循环;随后在某一次反复的时候,进行某种形式的"步进",即执行迭代因子。
    - 1.初始表达式设置循环变量的初值;
    - 2.条件判断部分为任意布尔表达式;
    - 3.迭代因子控制循环变量的增减;

for循环在执行条件判定后,先执行的循环体部分,再执行步进。

无限循环(也称为"死循环")基本格式如下:
    for {
        循环体语句
    }

for循环可以通过break、goto、return、panic语句强制退出循环。

Go语言中可以使用for range遍历数组、切片、字符串、map及通道(channel),其返回值有以下规律:
    (1)数组、切片、字符串返回索引和值。
    (2)map返回键和值。
    (3)通道(channel)只返回通道内的值。

温馨提示:
    - 1.for循环的初始化表达式,不能用var定义变量的形式,要用":=";
    - 2.for循环作用就是让程序员写代码的效率提高了(说白了,只是让程序员写代码简洁而已),但是底层该怎么执行还是怎么执行的,底层效率没有任何提高;

2 for循环引入

package main

import "fmt"

func main() {
    // 实现一个功能,求和: 1,3,5,7,9

    // 实现方式一: 变量定义太多啦!
    var (
        a    int = 1
        b        = 3
        c        = 5
        d        = 7
        e        = 9
        sum1     = 0
    )

    sum1 += a
    sum1 += b
    sum1 += c
    sum1 += d
    sum1 += e

    fmt.Printf("sum1 = %d\n", sum1)

    // 实现方式二: 重复代码过多
    var (
        i    int = 1
        sum2     = 0
    )

    sum2 += i
    i += 2

    sum2 += i
    i += 2

    sum2 += i
    i += 2

    sum2 += i
    i += 2

    sum2 += i
    fmt.Printf("sum2 = %d\n", sum2)

    // 实现方式三: 利用for循环解决问题
    var sum3 int = 0

    for x := 1; x <= 9; x += 2 {
        sum3 += x
    }

    fmt.Printf("sum3 = %d\n", sum3)

    /*
        温馨提示:
            - 1.for循环的初始化表达式,不能用var定义变量的形式,要用":=";
            - 2.for循环作用就是让程序员写代码的效率提高了(说白了,只是让程序员写代码简洁而已),但是底层该怎么执行还是怎么执行的,底层效率没有任何提高;
    */

    // for循环的变种写法,for循环语法非常灵活。
    var (
        sum4 int = 0
        y        = 1 // 变量的初始化
    )

    for y <= 9 { // 条件表达式,判断条件
        sum4 += y // 循环体
        y += 2    // 迭代因子
    }

    fmt.Printf("sum4 = %d\n", sum4)

    // x变量无法访问,但是y变量可以被访问。
    // fmt.Printf("x = %d\n", x)
    fmt.Printf("y = %d\n", y)
}

3.for循环原理

如上图所示,是for循环的执行顺序图解。

在经历5次循环之后,该进行第6次循环时i的值变为11,然后11不满足i<=9的条件,返回结果为false,因此不再执行循环体的代码,因此最终sum3的结果为25。

4.for死循环案例

package main

import (
    "fmt"
    "time"
)

func main() {
    var count int64 = 0

    // 死循环
    for {
        time.Sleep(1 * time.Second) // 每次睡眠1秒钟,用于模拟打游戏的时间!

        count++

        fmt.Printf("第【%d】次复活\n", count)
        if count == 3 {
            fmt.Println("闯关失败,即将重新开始闯关!")
            count = 0
        }
    }
}

二 .for range键值循环案例

1 for range概述

for range结构是GO语言特有的一种迭代结构,在许多情况下都非常有用。

for range可以遍历数组,切片,字符串,map及channel。for range语法上类似于其他语言中的foreach语句。

2 for range遍历字符串

package main

import (
    "fmt"
)

func main() {
    // 暂时先不要用中文测试,因为对于方式一的遍历有影响,对于方式二的没有影响
    // teacher := "JasonYin2020"
    teacher := "JasonYin2020尹正杰"

    // 方式一: 普通for循环,按照字节进行遍历输出的,如果想要使用这种方式遍历汉字,等学完切片再处理不迟。
    // for index := 0; index < len(teacher); index++ {
    //     fmt.Printf("第【%d】个字符是: %c\n", index+1, teacher[index])
    // }

    // 方式二: 对teacher进行遍历,遍历的每个结果的索引值被k接受,每个结果的具体数值被v接受。
    for k, v := range teacher {
        fmt.Printf("第【%d】个字符是: %c\n", k, v)
    }
}

三.break关键字

1.break作用

- 1.switch分支中,每个case分支后都有break结束当前分支,但是在Go语言中break可以省略不写;;

- 2.break可以结束正在执行的for循环;

- 3.break的作用结束离他最近的循环;

2 break跳出循环

package main

import (
    "fmt"
)

func main() {
    var (
        age   uint8
        myAge uint8 = 29
    )

    for {
        fmt.Print("请猜测我的年龄,输入数字即可:>>> ")
        fmt.Scanln(&age)

        if age < myAge {
            fmt.Println("猜小了...")
        } else if age > myAge {
            fmt.Println("猜大了...")
        } else {
            fmt.Printf("恭喜您,猜对啦,我的年龄是: %d,你是一个好人!\n", myAge)
            // break可以结束正在执行的for循环
            break
        }
    }

    fmt.Println("猜年龄程序运行结束,欢迎下次使用~")
}

3.break退出嵌套for循环

package main

import "fmt"

func main() {
    for i := 1; i <= 3; i++ {
        for j := 7; j <= 9; j++ {
            fmt.Printf("i: %d, j:%d \n", i, j)
            if i == 2 && j == 8 {
                // 此处break的作用就是结束离它最近的for循环。
                break
            }
        }
    }

    fmt.Println("程序运行结束啦......")
}

4 break退出指定的标签

package main

import "fmt"

func main() {

    /*
        温馨提示:
            1.一旦定义标签,则必须在后续的代码中引用标签,否则就会抛出异常:  label <LABEL_NAME> defined and not used
            2.本案例的"haha"标签其实是可以不定义的,因为break默认就是退出最近一层的for循环哟;此处我故意这样写你为了加深大家的理解;

    */

xixi: // 定义一个名为"xixi"的标签
    for i := 1; i <= 5; i++ {
    haha: // 定义一个名为"haha"的标签
        for j := 7; j <= 9; j++ {
            fmt.Printf("i: %d, j:%d \n", i, j)
            if i == 1 && j == 8 {
                // 结束指定标签对应的循环
                break haha
            }
            if i == 3 && j == 8 {
                // 结束指定标签对应的循环
                break xixi
            }
        }
    }

    fmt.Println("程序运行结束啦......")
}

四.continue关键字

1 continue作用

- 1.结束本次循环,继续下一次循环;

- 2.

2 continue结束本次循环

package main

import (
    "fmt"
)

func main() {

    var (
        number int = 0
    )

    fmt.Print("请输入一个范围以便于显示7的倍数:>>> ")
    fmt.Scanln(&number)

    for i := 0; i < number; i++ {
        if i%7 != 0 {
            // 结束本次循环,继续下一次循环
            continue
        } else {
            fmt.Printf("【%d】是7的倍数\n", i)
        }
    }

    fmt.Println("数7游戏运行结束啦......")
}

3 continue结束嵌套for循环

package main

import "fmt"

func main() {
    for i := 1; i <= 3; i++ {
        for j := 7; j <= 9; j++ {

            if i == 2 && j == 8 {
                // 此处continue的作用就是结束本次离它最近的for循环,然后继续下一次离它最近的for循环
                continue
            }

            fmt.Printf("i: %d, j:%d \n", i, j)
        }
    }

    fmt.Println("程序运行结束啦......")

}

4 continue结束指定的标签

package main

import "fmt"

func main() {

    /*
        温馨提示:
            1.一旦定义标签,则必须在后续的代码中引用标签,否则就会抛出异常:  label <LABEL_NAME> defined and not used
            2.本案例的"haha"标签其实是可以不定义的,因为continue默认就是跳出最近一层的for循环哟;此处我故意这样写你为了加深大家的理解;

    */

xixi: // 定义一个名为"xixi"的标签
    for i := 1; i <= 5; i++ {
    haha: // 定义一个名为"haha"的标签
        for j := 7; j <= 9; j++ {

            if i == 1 && j == 8 {
                // 结束指定标签对应的循环
                continue haha
            }
            if i == 3 && j == 8 {
                // 结束指定标签对应的循环
                continue xixi
            }

            fmt.Printf("i: %d, j:%d \n", i, j)
        }
    }

    fmt.Println("程序运行结束啦......")
}

五.goto关键字

1 goto概述

Golang中的goto语句通过标签进行代码间的无条件跳转。

goto语句通常与条件语句配合使用,可用来实现条件转移,goto语句可以在快速跳出循环、避免重复退出上有一定的帮助。

Go语言中使用goto语句能简化一些代码的实现过程。 


温馨提示:
    1.goto在汇编语言使用较多,在高级语言中使用较少;
    2.在Go程序设计中一般不建议使用goto语句,以免造成程序流程的混乱。

2 goto测试样例

package main

import "fmt"

func main() {

    var (
        a int = 10
        b     = 5
    )

    fmt.Println("hello golang1")
    fmt.Println("hello golang2")
    if a > b {
        // goto一般配合条件结构一起使用,跳转到指定标签
        goto xixi
    }
    fmt.Println("hello golang3")
    fmt.Println("hello golang4")
    fmt.Println("hello golang5")
    fmt.Println("hello golang6")
    fmt.Println("hello golang7")
xixi:
    fmt.Println("hello golang8")
    fmt.Println("hello golang9")

}

3 goto跳转到指定标签

package main

import (
    "fmt"
)

func main() {

    // 在不使用goto指令时,定义一个标志位,用来判断是否结束外层嵌套for循环。
    flag := false

    for i := 1; i < 5; i++ {
        for j := 7; j < 9; j++ {
            if i == 2 && j == 8 {
                flag = true
                break
            }
            fmt.Printf("%d -- %d \n", i, j)
        }
        // 通过标志位来判断是否跳出外层for循环
        if flag {
            break
        }
    }
    fmt.Printf("通过标志位[flag = %t]退出,嵌套for循环结束啦....\n", flag)

    for i := 1; i < 5; i++ {
        for j := 7; j < 9; j++ {
            if i == 2 && j == 8 {
                goto haha
            }
            fmt.Printf("%d -- %d \n", i, j)
        }

    }

    // 定义一个标签名为"haha"(该名称可以自定义哟),标签需要被引用否则会报错
    // 实际工作中,尽量少用goto指令,尽管它看上去比上面使用flag的方式语法更简洁,但用的多容易混乱哟!
haha:
    fmt.Println("程序运行结束,嵌套for循环结束啦....")

}

六.return关键字

1 return概述

return用于直接结束当前函数,不在继续往后执行代码。

2 return测试样例

package main

import "fmt"

func main() {

    for i := 1; i <= 100; i++ {
        fmt.Printf("当前是第[%d]次循环\n", i)

        if i == 5 {
            // 直接结束当前函数,不在继续往后执行代码
            return
        }
    }

    // 由于上面已经return了,因此本行代码是不会被执行的哟~
    fmt.Println("程序运行结束")
}

七.练习题

1.计算100以内的偶数的和

package main

import (
    "fmt"
)

func main() {
    // 计算100以内的偶数的和
    for number := 0; number <= 100; number++ {
        if number%2 == 0 {
            fmt.Printf("【%d】是偶数\n", number)
        }
    }
}

2.统计300-500以内的所有素数

package main

import (
    "fmt"
)

func main() {
    // 素数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数

    // 统计素数的个数
    var count int = 0

    for i := 300; i < 500; i++ {

        // 定义标志位,如果找到了素数,则为true,默认我们就认为本次循环找到了素数
        flag := true

        // 判断i是否为素数
        for j := 2; j < i; j++ {
            if i%j == 0 {
                flag = false
                break
            }
        }
        // 打印素数
        if flag {
            count++
            // fmt.Printf("%d是素数\n", i)
        }
    }

    fmt.Printf("300-500以内,共计有[%d]个素数!", count)
}

3.编写代码打印99乘法表

package main

import (
    "fmt"
)

func main() {
    for i := 1; i <= 9; i++ {
        for j := 1; j <= i; j++ {
            fmt.Printf("%d x %d = %d\t", j, i, i*j)
        }
        fmt.Println()
    }
}
目录
相关文章
|
14天前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
47 4
Golang语言之管道channel快速入门篇
|
14天前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
42 3
Golang语言之gRPC程序设计示例
|
14天前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
37 4
|
14天前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
23 4
Golang语言goroutine协程篇
|
14天前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
20 3
Golang语言之Prometheus的日志模块使用案例
|
14天前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
37 4
Golang语言文件操作快速入门篇
|
14天前
|
Go
Golang语言错误处理机制
这篇文章是关于Golang语言错误处理机制的教程,介绍了使用defer结合recover捕获错误、基于errors.New自定义错误以及使用panic抛出自定义错误的方法。
36 3
|
14天前
|
Go
Golang语言之函数(func)进阶篇
这篇文章是关于Golang语言中函数高级用法的教程,涵盖了初始化函数、匿名函数、闭包函数、高阶函数、defer关键字以及系统函数的使用和案例。
16 3
Golang语言之函数(func)进阶篇
|
14天前
|
Go
Golang语言之函数(func)基础篇
这篇文章深入讲解了Golang语言中函数的定义和使用,包括函数的引入原因、使用细节、定义语法,并通过多个案例展示了如何定义不返回任何参数、返回一个或多个参数、返回值命名、可变参数的函数,同时探讨了函数默认值传递、指针传递、函数作为变量和参数、自定义数据类型以及返回值为切片类型的函数。
17 2
Golang语言之函数(func)基础篇
|
14天前
|
Go
Golang语言之映射(map)快速入门篇
这篇文章是关于Go语言中映射(map)的快速入门教程,涵盖了map的定义、创建方式、基本操作如增删改查、遍历、嵌套map的使用以及相关练习题。
21 5