目 录CONTENT

文章目录

Go学习系列07-流程控制

cplinux98
2022-11-03 / 0 评论 / 0 点赞 / 33 阅读 / 3,192 字 / 正在检测是否收录...

go中的流程控制

go语言中的流程控制包含

  • 顺序结构
    • 按照顺序执行,不发送跳转
  • 选择结构
    • 依据是否满足条件,有选择的执行相应的功能
  • 循环结构
    • 依据条件是否满足,循环多次执行某段代码

顺序结构

就是按照代码编写的顺序来执行,中间没有任何的判断和跳转

// 代码是从上到下依次执行的
func main() {
	var a int = 4
	var b int32
	var c float32
	var ptr *int
	fmt.Printf("a type is :%T\n", a)
	fmt.Printf("b type is :%T\n", b)
	fmt.Printf("c type is :%T\n", c)

	ptr = &a
	fmt.Printf("a value is : %d\n", a)
	fmt.Printf("ptr is : %d\n", ptr)
	fmt.Printf("ptr is : %d\n", *ptr)
}

注意:代码中使用到其他的变量,必须要在该代码上面声明

// 正确方式
func main() {
	var a int = 4
	var b int = 10
    var c int = b + a
	fmt.Printf("c type is :%d\n", c)
}
// 错误方式
func main() {
    var c int = b + a
    var a int = 4
    var b int = 10
	fmt.Printf("c type is :%d\n", c)
}

选择结构

常用的选择结构就是if-else,满足某些条件下,才能做某些事情,不满足就无法去做

if结构

对于if结构来说,就是看“条件”和“隐藏条件”

if后面的条件为真,就可以执行if代码块内的代码

if true {
    fmt.Println("hello world")
}

if后面可以直接接运算符

var age int = 20
if age >= 18 {
    fmt.Println("你已经成年")
}

if也支持1个初始化语句,初始化语句和判断条件以“分号”分割

if age := 20; age >= 18 {
    fmt.Println("你已经成年")
}

if练习

让用户输入用户名和密码,如果用户名为admin,密码为mypass,则提示登录成功

package main

import "fmt"

//让用户输入用户名和密码,如果用户名为admin,密码为mypass,则提示登录成功
func main() {
	var username string
	var password string
	fmt.Printf("username: ")
	_, _ = fmt.Scanf("%s \n", &username)
	fmt.Printf("password: ")
	_, _ = fmt.Scanf("%s", &password)
	if username == "admin" {
		if password == "mypass" {
			fmt.Println("登录成功")
		}
	}
}
//username: admin
//password: mypass
//登录成功

if-else结构

在使用if的时候,只有if后面的条件为true才会执行代码块里的内容,如果想要不为true时执行其他内容,就需要用到else。

if score := 80; score >=60 {
    fmt.Println("及格了")
} else { // else必须在这个位置,
    // 隐含了条件 score < 60
    fmt.Println("没及格")
}

if嵌套

if的嵌套不宜过多,建议控制在3层内,否则代码的可读性会变差,有可能导致逻辑不清晰,出现异常bug

if xx {
    if yy {
        
    } else {
        if zz {
            
        }
    }
}

举例

对学员的结业考试成绩评测

成绩>=90 :A    
90>成绩>=80 :B   
80>成绩>=70 :C 
70>成绩>=60 :D 
成绩<60 :E 
func main() {
	var score int
	fmt.Println("请输入考试成绩:")
	_, _ = fmt.Scanf("%d", &score)
	if score >= 90 {
		fmt.Println("A")
	} else {
		// 这里就隐含了条件 score < 90
		if score >= 80 {
			fmt.Println("B")
		} else {
			// 这里隐含了条件 score < 80
			if score >= 70 {
				fmt.Println("C")
			} else {
				// 这里隐含了条件 score < 70
				if score >= 60 {
					fmt.Println("D")
				} else {
					// 这里隐含了条件 score < 60
					fmt.Println("E")
				}
			}
		}
	}
}

if-else if结构

我们发现上面的else里面嵌套的if判断中的else感觉多余的样子,是否可以直接在一层嵌套里直接判断呢,这就要用到if了

if xxx {
    
} else if yyy {
    
} else if zzz {
    
} else {
    
}

这样的结构,既可以让多个if-else在同一层内,又可以满足隐藏的关系


func main() {
	var score int
	fmt.Println("请输入考试成绩:")
	_, _ = fmt.Scanf("%d", &score)
	if score >= 90 {
		fmt.Println("A")
	} else if score >= 80 { // 这里也是一样的,隐含了score < 90的条件
		fmt.Println("B")
	} else if score >= 70 {
		fmt.Println("C")
	} else if score >= 60 {
		fmt.Println("D")
	} else {
		fmt.Println("E")
	}
}

这样的代码结构就很清晰,阅读性比上面的强

简单总结一下三种if的适用条件

  • if 适用于一种情况的判断
  • if-else 适用于两种情况的判断
  • if-else if 适用于多种情况判断,并且判断都是对区间范围进行判断

switch结构

对于定值的判断,使用switch是一个不错的选择

switch xx {
case 10:
    fmt.println("10")
case 20:
    fmt.println("20")
default:
    fmt.println("end")
}

switch的执行流程是:

  • 程序执行到switch处,首先将变量或表达式的值计算出来
  • 然后拿着这个值依次根case后面的值进行对比
    • 对比成功,则结束switch
    • 对比失败,进入下一个case
  • 如果case都对比失败,会查看是否有default
    • 有则会执行default内代码,相当于兜底的
    • 无则会结束switch

switch也可以像if一样,在关键词后直接定义和使用变量

fallthrough

中文意思为“贯穿”,可以放在满足条件的case最后一行,即使下一行case不满足,也会执行里面的代码,但fallthrough不能放在最后一个case里面,因为没有可以贯穿的了

func main() {
	switch score := 80; score {
	case 80:
		fmt.Println("80")
		fallthrough
	case 70:
		fmt.Println("70")
	case 60:
		fmt.Println("60")
	case 50:
		fmt.Println("50")
	case 40:
		fmt.Println("40")
	case 30:
		fmt.Println("30")
	}
}

输出结果为

80
70

类型转换

switch语句还可以被用于type switch(类型转换),用来判断某个interface(里面可以存储任意类型)变量里面的具体类型

switch x.(type) {
case type1:
    fmt.Println("x type is type1")
case type2:
    fmt.Println("x type is type2")
}
func main() {
	//var x interface{} // x type is nil
	var x interface{}
	x = float64(3) // x type is bool or float64
	switch x.(type) {
	case int:
		fmt.Println("x type is int")
	case nil:
		fmt.Println("x type is nil")
	case string:
		fmt.Println("x type is string")
	case bool, float64:
		fmt.Println("x type is bool or float64")
	default:
		fmt.Println("unknown")
	}
}

总结

switch和case后的内容

  • switch后面不写,则默认为true,下面的case则会判断最终结果是否为true
  • 可以是常量、变量、一个有返回值的函数
  • 在没有使用类型转换时,switch后面最终结果类型要和case最终结果类型一致
  • case可以接多个表达式,只要满足其中一个即可
  • case如果是常量(字面量),要求case之间不能有重复
  • switch后面可以直接声明/定义一个变量,和if一样,但是不推荐这样使用,因为switch本身就是要判断这个,既然已经定义了那判断就多此一举

循环结构

循环就是重复的做同一件事情

for结构

for 初始语句;条件表达式;结束语句{
    循环执行的代码
}
  • 初始语句: 定义一个循环的变量,记录循环的次数
    • 只执行一次
  • 条件表达式:一般为循环的条件,循环多少次
    • 根据条件表达式的返回值来判断是否执行循环代码(true执行,false终止)
  • 结束语句:一般为改变循环条件的代码,使循环条件不再成立
    • 循环代码执行完成后,会执行结束语句,对条件表达式内的变量进行修改,然后进入下一次循环的判断,也就是判断条件表达式是否成立
  • 循环执行的代码:就是我们要重复做的事情
func main() {
	for i := 0; i <= 10; i++ {
		fmt.Println(i)
	}
}

for处理顺序

func init1(n *int) int {
	fmt.Println("初始化运行")
	return 0
}

func expr2(n int) bool {
	fmt.Printf("条件表达式运行 %d\n", n)
	return n <= 10
}

func end3(n *int) *int {
	fmt.Println("结束语句运行++++")
	*n++
	return n
}

func main() {
	var i int
	for init1(&i); expr2(i); end3(&i) {
		fmt.Println(i)
	}
}

最后的结果是

初始化运行
条件表达式运行 0
0
结束语句运行++++
条件表达式运行 1
1
结束语句运行++++
条件表达式运行 2
2
结束语句运行++++
条件表达式运行 3
3
结束语句运行++++
条件表达式运行 4
4
结束语句运行++++
条件表达式运行 5
5
结束语句运行++++
条件表达式运行 6
6
结束语句运行++++
条件表达式运行 7
7
结束语句运行++++
条件表达式运行 8
8
结束语句运行++++
条件表达式运行 9
9
结束语句运行++++
条件表达式运行 10
10
结束语句运行++++
条件表达式运行 11

for变形

初始语句、条件表达式、结束语句3种组成部分都是可选的,所以可以演化成4种不同的写法

  • // 省略初始化
    func main() {
    	i := 0
    	for ; i <= 10; i++ {
    		fmt.Println(i)
    	}
    }
    
  • // 省略条件表达式就是默认为true,形成无限循环,需要在循环代码中打破循环
    func main() {
    	i := 0
    	for ; ; i++ {
    		if i > 10 {
    			break
    		}
    		fmt.Println(i)
    	}
    }
    
  • // 只保留条件判断,结束语句就在循环代码中写
    // 有点像python的 while
    func main() {
    	var i int
    	for i <= 10 {
    		fmt.Println(i)
    		i++
    	}
    }
    
    
  • // 三种表达式都忽略,这种更像python的while
    func main() {
    	var i int
    	for {
    		if i > 10 {
    			break
    		}
    		fmt.Println(i)
    		i++
    	}
    }
    
  • // 使用range来遍历
    func main() {
    	str := "1234567890"
    	for i, value := range str {
    		fmt.Printf("第 %d位的字符是%c \n", i, value)
    	}
    }
    
    • range可以对string、slice、array、map、channel等进行遍历
    • array、slice、string返回索引和值
    • map返回key和value
    • channel返回通道内的值

for嵌套

for里面也可以使用for循环

for xx;xx;xx {
    xxxxxx
    for yy;yy;yy {
        yyyyyy
    }
}

示例,使用for循环打印99乘法表

func main() {
	for i := 1; i <= 9; i++ {
		for j := 1; j <= i; j++ {
			fmt.Printf("%d*%d=%d ", j, i, i*j)
		}
		fmt.Println()
	}
}

效果

1*1=1
1*2=2 2*2=4 
1*3=3 2*3=6 3*3=9 
1*4=4 2*4=8 3*4=12 4*4=16 
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 

while和do…while的实现

Go语言中没有while和do…while语法,但是我们可以通过for循环来实现相应的效果》

while循环(先循环再做)

for {
    if i>10 {
        break  // 跳出循环
    }
    i++
}

do…while(先做再循环)

for {
	i++
    if i>10 {
        break
    }
}

跳转语句

break

用于终止某个语句块的执行,用于中断当前for循环或跳出switch语句

image-20221103201619525

  • break默认会跳出最近的for循环
  • break后面可以指定标签,跳出标签对应的for循环
lable2:
for{
    for i := 0 ; i < 10 ; i++ {
        if i == 2 {
            break lable2
        }
    }
}

continue

跳出当前循环,执行下一次循环

image-20221103202628739

  • 用于结束本次循环,继续执行下一次循环
  • 在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环

和break的区别是

  • break语句无条件跳出并结束当前循环,然后执行循环后的语句
  • continue语句跳过当前循环,开始执行下一次循环

goto

go语言中使用goto可以无条件转移到程序指定的行,通常配合条件语句使用,用来实现条件转移、构成循环、跳出循环体等功能

在go程序设计中一般不主张使用goto语句,以免造成程序流程的混乱,使理解和调试程序都产生困难

image-20221103203038564

LABEL: statement
goto LABEL

return

在使用方法或者函数时,表示跳出所在的方法或函数

  • 函数中的循环体使用return,可以直接中断循环体的运行
  • return在main函数中,表示终止main函数,也就是终止程序
0

评论区