【go基础】程序流程控制

本文详细介绍了Go语言中的程序流程控制,包括顺序控制、分支控制(if、switch结构)、循环控制(for循环、break、continue),以及switch结构中的fallthrough用法。内容涵盖从简单的条件判断到复杂的嵌套循环,是学习Go语言控制流的重要参考资料。
摘要由CSDN通过智能技术生成

程序流程控制介绍

程序中,程序运行的流程控制决定程序是如何执行的,是我们必须掌握的,主要有三大流程控制语句。

  1. 顺序控制
  2. 分支控制
  3. 循环控制

1.顺序控制

没有判断,也没有跳转.因此程序按照默认(从上到下))的流程执行,即顺序控制。

2.分支控制(if)

2.1单分支

if age > 18 {
		fmt.Println("你年龄大于18,要对自己的行为负责!")
	}
if age := 20; age > 18 {
		fmt.Println("你年龄大于18,要对自己的行为负责!")
	}

2.2 双分支

	if age > 18 {
		fmt.Println("你年龄大于18~....")
	} else {
		fmt.Println("你的年龄不大这次放过你了")
	}

2.3多分支

package main

import "fmt"

func main() {
    var age int = 23
    if age == 25 {
        fmt.Println("true")
    } else if age < 25 {
        fmt.Println("too small")
    } else {
        fmt.Println("too big")
    }
}

2.4 if 嵌套

if 布尔表达式 1 {
   /* 在布尔表达式 1 为 true 时执行 */
   if 布尔表达式 2 {
      /* 在布尔表达式 2 为 true 时执行 */
   }
}
package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int = 200
 
   /* 判断条件 */
   if a == 100 {
       /* if 条件语句为 true 执行 */
       if b == 200 {
          /* if 条件语句为 true 执行 */
          fmt.Printf("a 的值为 100 , b 的值为 200\n" );
       }
   }
   fmt.Printf("a 值为 : %d\n", a );
   fmt.Printf("b 值为 : %d\n", b );
}

3.分支控制(switch 结构)

switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。
switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough 。
switch 后也可以不带表达式,类似 if --else 分支来使用

3.1 switch var

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

变量 var1 可以是任何类型,而 val1 和 val2 则可以是同类型的任意值。类型不被局限于常量或整数,但必须是相同的类型;或者最终结果为相同类型的表达式。

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var grade string = "B"
   var marks int = 90

   switch marks {
      case 90: grade = "A"
      case 80: grade = "B"
      case 50,60,70 : grade = "C"
      default: grade = "D"  
   }

   switch {
      case grade == "A" :
         fmt.Printf("优秀!\n" )    
      case grade == "B", grade == "C" :
         fmt.Printf("良好\n" )      
      case grade == "D" :
         fmt.Printf("及格\n" )      
      case grade == "F":
         fmt.Printf("不及格\n" )
      default:
         fmt.Printf("差\n" );
   }
   fmt.Printf("你的等级是 %s\n", grade );      
}
优秀!
你的等级是 A

3.2 switch I.(Type){}

switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。

Type Switch 语法格式如下:

switch x.(type){
    case type:
       statement(s);      
    case type:
       statement(s); 
    /* 你可以定义任意个数的case */
    default: /* 可选 */
       statement(s);
}

实例

package main

import "fmt"

func main() {
   var x interface{}
     
   switch i := x.(type) {
      case nil:  
         fmt.Printf(" x 的类型 :%T",i)                
      case int:  
         fmt.Printf("x 是 int 型")                      
      case float64:
         fmt.Printf("x 是 float64 型")          
      case func(int) float64:
         fmt.Printf("x 是 func(int) 型")                      
      case bool, string:
         fmt.Printf("x 是 bool 或 string 型" )      
      default:
         fmt.Printf("未知型")    
   }  
}

执行结果

x 的类型 :<nil>

3.4 fallthrough

使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。

package main

import "fmt"

func main() {

    switch {
    case false:
            fmt.Println("1、case 条件语句为 false")
            fallthrough
    case true:
            fmt.Println("2、case 条件语句为 true")
            fallthrough
    case false:
            fmt.Println("3、case 条件语句为 false")
            fallthrough
    case true:
            fmt.Println("4、case 条件语句为 true")
    case false:
            fmt.Println("5、case 条件语句为 false")
            fallthrough
    default:
            fmt.Println("6、默认 case")
    }
}

执行结果

2case 条件语句为 true
3case 条件语句为 false
4case 条件语句为 true

3.5 其他细节

  1. switch 的 default 不论放在哪都是最后执行
  2. switch支持多条件匹配
  3. switch 和 if 的比较
  1. 如果判断的具体数值不多,而且符合整数、浮点数、字符、字符串这几种类型。建议使用 swtich
    语句,简洁高效。
  2. 其他情况:对区间判断和结果为 bool 类型的判断,使用 if,if 的使用范围更广。

4.分支控制(select结构,待完善)

select 是 Go 中的一个控制结构,类似于 switch 语句。
select 语句只能用于通道操作,每个 case 必须是一个通道操作,要么是发送要么是接收。
select 语句会监听所有指定的通道上的操作,一旦其中一个通道准备好就会执行相应的代码块。
随机性:如果多个通道都准备好,那么 select 语句会随机选择一个通道执行。
如果所有通道都没有准备好(阻塞),那么执行 default 块中的代码,并不会阻塞。但是如果没有 default 语句,则会阻塞直到某个信道操作成功为止。

语法

select {
  case <- channel1:
    // 执行的代码
  case value := <- channel2:
    // 执行的代码
  case channel3 <- value:
    // 执行的代码

    // 你可以定义任意数量的 case

  default:
    // 所有通道都没有准备好,执行的代码
}
  • 每个 case 都必须是一个通道
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通道可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,select 会随机公平地选出一个执行,其他不会执行。
  • 否则
  • 如果有 default 子句,则执行该语句。

  • 如果没有 default 子句,select 将阻塞,直到某个通道可以运行;Go 不会重新对channel 或值进行求值。

select 语句应用演示:

package main

import (
	"fmt"
	"time"
)

func main() {

	c1 := make(chan string)
	c2 := make(chan string)

	go func() {
		time.Sleep(1 * time.Second)
		c1 <- "one"
	}()
	go func() {
		time.Sleep(2 * time.Second)
		c2 <- "two"
	}()

	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-c1:
			fmt.Println("received", msg1)
		case msg2 := <-c2:
			fmt.Println("received", msg2)
		}
	}
}

结果

received one
received two

5. 循环语句

5.1 for循环

5.1.1 for init; condition; post { }

init: 一般为赋值表达式,给控制变量赋初值;
condition: 关系表达式或逻辑表达式,循环控制条件;
post: 一般为赋值表达式,给控制变量增量或减量。

1、先对表达式 1 赋初值;
2、判别赋值表达式 init 是否满足给定条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。

计算 1 到 10 的数字之和:

package main

import "fmt"

func main() {
   sum := 0
      for i := 0; i <= 10; i++ {
         sum += i
      }
   fmt.Println(sum)
}  //55

写法2

	j := 1 //循环变量初始化
	for j <= 10 { //循环条件
		
		fmt.Println("你好,尚硅谷~", j)
		j++ //循环变量迭代
	}
5.1.2 for - range 格式: for key, value := range oldMap{}

for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

package main
import "fmt"

func main() {
   strings := []string{"google", "runoob"}
   for i, s := range strings {
      fmt.Println(i, s)
   }

   numbers := [6]int{1, 2, 3, 5}
   for i,x:= range numbers {
      fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
   }  
}
0 google
1 runoob
第 0 位 x 的值 = 11 位 x 的值 = 22 位 x 的值 = 33 位 x 的值 = 54 位 x 的值 = 05 位 x 的值 = 0
5.1.3 for - range 格式中 key 和 value 的省略。

如果只想读取 key,格式如下:for key := range oldMap 或者 for key, _ := range oldMap
如果只想读取 value,格式如下:for _, value := range oldMap

package main
import "fmt"

func main() {
    map1 := make(map[int]float32)
    map1[1] = 1.0
    map1[2] = 2.0
    map1[3] = 3.0
    map1[4] = 4.0
   
    // 读取 key 和 value
    for key, value := range map1 {
      fmt.Printf("key is: %d - value is: %f\n", key, value)
    }

    // 读取 key
    for key := range map1 {
      fmt.Printf("key is: %d\n", key)
    }

    // 读取 value
    for _, value := range map1 {
      fmt.Printf("value is: %f\n", value)
    }
}
key is: 4 - value is: 4.000000
key is: 1 - value is: 1.000000
key is: 2 - value is: 2.000000
key is: 3 - value is: 3.000000
key is: 1
key is: 2
key is: 3
key is: 4
value is: 1.000000
value is: 2.000000
value is: 3.000000
value is: 4.000000

5.2 for 实现 do…while :

var j int = 1
	for {
		fmt.Println("hello,ok", j)
		j++ //循环变量的迭代
		if j > 10 {
			break //break 就是跳出for循环
		}
	}

5.3 for 实现while for condition { }

init 和 post 参数是可选的,我们可以直接省略它,类似 While 语句。

package main

import "fmt"

func main() {
   sum := 1
   for sum <= 10 {
      sum += sum
   }
   fmt.Println(sum)

   // 这样写也可以,更像 While 语句形式
   for sum <= 10{
      sum += sum
   }
   fmt.Println(sum)
}
var i int = 1
	for {
		if i > 10 { //循环条件
			break // 跳出for循环,结束for循环
		}
		fmt.Println("hello,world", i)
		i++ //循环变量的迭代
	}

	fmt.Println("i=", i)

5.4 for 死循环for { }

package main

import "fmt"

func main() {
   sum := 0
   for {
      sum++ // 无限循环下去
   }
   fmt.Println(sum) // 无法输出
}

5.5 循环嵌套

使用循环嵌套来输出 2 到 100 间的素数:

package main

import "fmt"

func main() {
	/* 定义局部变量 */
	var i, j int

	for i = 2; i < 100; i++ {
		for j = 2; j <= (i / j); j++ {
			if i%j == 0 {
				break // 如果发现因子,则不是素数
			}
		}
		if j > (i / j) {
			fmt.Printf("%d  是素数\n", i)
		}
	}
}

九九乘法表:

package main 

import "fmt"

func main() {
    for m := 1; m < 10; m++ {
    /*    fmt.Printf("第%d次:\n",m) */
        for n := 1; n <= m; n++ {
            fmt.Printf("%dx%d=%d ",n,m,m*n)
        }
        fmt.Println("")
    }
}

5.6 for 循环的实例——遍历字符串

var str string = "hello,world!北京"
	for i := 0; i < len(str); i++ {
		fmt.Printf("%c \n", str[i]) //使用到下标...
	}
var str string = "hello,world!北京"
	str2 := []rune(str) // 就是把 str 转成 []rune
	for i := 0; i < len(str2); i++ {
		fmt.Printf("%c \n", str2[i]) //使用到下标...
	}

//字符串遍历方式2-for-range
	str = "abc~ok上海"
	for index, val := range str {
		fmt.Printf("index=%d, val=%c \n", index, val)
	}

6. 循环控制语句

6.1 break

6.1.1 用于循环语句中跳出当前所在的for循环(只跳出一层循环),并开始执行循环之后的语句。

在变量 a 大于 15 的时候跳出循环:

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 10

   /* for 循环 */
   for a < 20 {
      fmt.Printf("a 的值为 : %d\n", a);
      a++;
      if a > 15 {
         /* 使用 break 语句跳出循环 */
         break;
      }
   }
}
a 的值为 : 10
a 的值为 : 11
a 的值为 : 12
a 的值为 : 13
a 的值为 : 14
a 的值为 : 15

实例2

func main() {

	for i := 1; i <= 3; i++ {
		fmt.Printf("外层i: %d\n", i)
		for j := 11; j <= 13; j++ {
			fmt.Printf("内层j: %d\n", j)
			break //跳出当前for循环,不执行j++
		}
		fmt.Println("break后处于该位置")
	}
	fmt.Println("end")
}
外层i: 1         
内层j: 11        
break后处于该位置
外层i: 2         
内层j: 11        
break后处于该位置
外层i: 3         
内层j: 11        
break后处于该位置
end         
6.1.2 在多重循环中,可以用标号 label 标出想 break 的循环(可一次性跳出多个循环,跳出当前lable)。

lable的定义:lablename:

package main

import "fmt"

func main() {

   // 使用标记
	fmt.Println("---- break label ----")
re:
	for i := 1; i <= 3; i++ {
		fmt.Printf("外层i: %d\n", i)
		for j := 11; j <= 13; j++ {
			fmt.Printf("内层j: %d\n", j)
			break re
		}
		fmt.Println("break后处于该位置吗?")
	}
	fmt.Println("end")
}
外层i: 1 
内层j: 11
end 

6.2 continue

6.2.1for condition; { }(while)中的continue
package main

import "fmt"

func main() {
	/* 定义局部变量 */
	var a int = 10
	b := 10
	/* for 循环 */
	for a < 15 {
		if b < 13 {
			/* 跳过此次循环 */
			b = b + 1
			continue
			fmt.Printf("b 的值为 : %d\n", b)
		}
		fmt.Printf("continue 到这个位置,当前 a 的值为 : %d\n", a)
		a++
	}
}

执行结果

continue 到这个位置,当前 a 的值为 : 10
continue 到这个位置,当前 a 的值为 : 11
continue 到这个位置,当前 a 的值为 : 12
continue 到这个位置,当前 a 的值为 : 13
continue 到这个位置,当前 a 的值为 : 14

6.2.2for init; condition; post { }中的continue

一个更有趣的例子:

package main

import "fmt"

func main() {
	/* 定义局部变量 */
	b := 1
	/* for 循环 */
	for a := 1; a < 5; a++ {
		if b < 3 {
			/* 跳过此次循环 */
			b = b + 1
			continue // continue 跳到了a++ ,然后直接到达下一次判定
			//只有当b>=3时,才能不执行continue,此时才会打出后文a的值
			fmt.Printf("b 的值为 : %d\n", b)
		}
		fmt.Printf("continue 到这个位置吗?当前 a 的值为 : %d,b的值为 :%d\n", a, b)
	}
}

执行结果

continue 到这个位置吗?当前 a 的值为 : 3,b的值为 :3
continue 到这个位置吗?当前 a 的值为 : 4,b的值为 :3

6.3 goto

Go 语言的 goto 语句可以无条件地转移到过程中指定的行。

goto 语句通常与条件语句配合使用。可用来实现条件转移, 构成循环,跳出循环体等功能。

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

goto 语法格式如下:

goto label;
..
.
label: statement;

在这里插入图片描述
在变量 a 等于 5 的时候跳过本次循环并回到循环的开始语句 LOOP 处:

package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 1

   /* 循环 */
   LOOP: for a <= 5 {
      if a == 3 {
         /* 跳过迭代 */
         a = a + 1
         goto LOOP
      }
      fmt.Printf("a的值为 : %d\n", a)
      a++    
   }  
}
a的值为 : 1
a的值为 : 2
a的值为 : 4
a的值为 : 5

for循环配合goto打印九九乘法表

package main

import "fmt"

// for循环配合goto打印九九乘法表
func gotoTag() {
	for m := 1; m < 10; m++ {
		n := 1
	LOOP:
		if n <= m {
			fmt.Printf("%dx%d=%d ", n, m, m*n)
			n++
			goto LOOP
		} else {
			fmt.Println("")
		}
		n++
	}
}

func main() {
	//print9x()
	gotoTag()
}

1x1=1
1x2=2 2x2=4                                                   
1x3=3 2x3=6 3x3=9                                             
1x4=4 2x4=8 3x4=12 4x4=16                                     
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25                             
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36                      
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49               
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64        
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81 
6.4 return

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

  1. 如果 return 是在普通的函数,则表示跳出该函数,即不再执行函数中 return 后面代码,也可以理解成终止函数。
  2. 如果 return 是在 main 函数,表示终止 main 函数,也就是说终止程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值