Go语言流程控制(一)

发布于:2024-05-08 ⋅ 阅读:(31) ⋅ 点赞:(0)

分支结构

if...else...语句

Go 语言中的 if...else 语句是一种基本的流程控制结构,用于根据条件执行不同的代码块。下面是关于 Go 语言中 if...else 语句的详细介绍:

基本语法

if 条件表达式 {
    // 当条件表达式为 true 时执行的代码
} else {
    // 当条件表达式为 false 时执行的代码
}

用法

1.基本的 if 语句

if score > 60 {
    fmt.Println("Pass")
}

2.if...else...语句

var ten int = 11
if ten > 10 {
    fmt.Println(">10")
} else {
    fmt.Println("<=10")
}

3.if...else if...else 链 

if score >= 90 {
    fmt.Println("Excellent")
} else if score >= 60 {
    fmt.Println("Pass")
} else {
    fmt.Println("Fail")
}

特殊写法

if 还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断,代码如下:

if num, err := someFunction(); err == nil {
    fmt.Println(num)
} else {
    fmt.Println(err)
}

这段代码是Go语言中一个非常典型的模式,用于处理那些可能会返回错误的情景,比如读取文件、网络操作或调用某些可能失败的函数。我来详细解释一下每一部分:

  1. 函数调用与同时声明变量:

    1num, err := someFunction()

    这一行做了两件事:

    • 调用了 someFunction() 函数。
    • 使用简短声明 := 同时声明了两个变量 num 和 err,并分别赋予了 someFunction() 返回的两个值。在Go中,一个函数可以返回多个值,这里假设 someFunction() 返回一个需要的数据(例如一个整数、字符串等,用 num 接收)和一个错误对象(用 err 接收)。如果函数执行成功,通常会返回 nil 作为错误值。
  2. 条件判断:

    if err == nil {

    这个条件检查 err 是否为 nil。在Go中,nil 表示没有错误,所以如果 err == nil 为真,意味着 someFunction() 调用成功。

  3. 成功分支:

    fmt.Println(num)

    如果没有错误(即 err == nil),就打印出成功获取到的数据 num

  4. 失败分支:

    else {
       fmt.Println(err)
    }

    如果有错误(即 err != nil),则执行这里的代码块,打印出错误信息。这样可以快速定位问题所在。

循环结构

for语句

for 循环的几种主要形式:

1.经典C风格的for循环:

for 初始化; 条件; 更新 {
    // 循环体
}

这种形式类似于C语言的for循环,其中:

  • 初始化:在循环开始之前执行一次,通常用于设置循环控制变量。
  • 条件:在每次循环迭代前检查,如果为 true 则执行循环体。
  • 更新:在每次循环体执行完毕后执行,通常用于改变循环控制变量。

用法

sum := 0
for i := 0; i < 10; i++ {
    sum += i
}

2.条件循环:

for 条件 {
    // 循环体
}

这种形式省略了初始化和更新部分,仅当给定的条件为 true 时执行循环体,相当于没有初始化和更新的简化版。

用法

var i int
for i <= 10 {
    i++
}

3.无限循环:

for {
    // 循环体
}

这种形式没有条件检查,因此会一直循环下去,除非在循环体内使用 break 语句跳出循环。

用法

var i int
for {
    if i > 10 {
        break
    }
    i++
}
for j := 0; j < 5; j++ {
    for i := 0; i < 10; i++ {
        if i > 5 {
            break JLoop
        }
        fmt.Println(i)
    }
}
JLoop:
// ...

上述代码中,break 语句终止的是 JLoop 标签处的外层循环。

4.for 中的初始语句——开始循环时执行的语句

初始语句是在第一次循环前执行的语句,一般使用初始语句执行变量初始化,如果变量在此处被声明,其作用域将被局限在这个 for 的范围内。

初始语句可以被忽略,但是初始语句之后的分号必须要写,代码如下:

step := 2
for ; step > 0; step-- {
    fmt.Println(step)
}
这段代码将 step 放在 for 的前面进行初始化,for 中没有初始语句,此时 step 的作用域就比在初始语句中声明 step 要大。

5.for 中的条件表达式——控制是否循环的开关

每次循环开始前都会计算条件表达式,如果表达式为 true,则循环继续,否则结束循环,条件表达式可以被忽略,忽略条件表达式后默认形成无限循环。

结束循环时带可执行语句的无限循环

下面代码忽略条件表达式,但是保留结束语句,代码如下:

var i int
for ; ; i++ {
    if i > 10 {
        break
    }
}

上面的代码还可以改写为更美观的写法,代码如下:

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

练习题:打印九九乘法表

package main
import "fmt"
func main() {
    // 遍历, 决定处理第几行
    for y := 1; y <= 9; y++ {
        // 遍历, 决定这一行有多少列
        for x := 1; x <= y; x++ {
            fmt.Printf("%d*%d=%d ", x, y, x*y)
        }
        // 手动生成回车
        fmt.Println()
    }
}

键值循环

在Go语言中,for循环有一种特殊形式,称为“键值循环”(key-value iteration),常用于遍历数组、切片、映射(map)、通道(channel)等集合类型,特别是当需要同时访问元素的索引或键以及对应的值时。这种循环形式使用关键字range

基本语法

for index, value := range collection {
   // 循环体
}

其中:

  • index:表示集合中当前元素的索引或映射中键的副本。
  • value:表示集合中当前元素的值或映射中对应键的值的副本。
  • collection:是要遍历的集合,可以是数组、切片、映射或通道。

遍历数组/切片

示例1:遍历切片
package main

import "fmt"

func main() {
    fruits := []string{"apple", "banana", "cherry"}
    for i, fruit := range fruits {
        fmt.Printf("Index: %d, Fruit: %s\n", i, fruit)
    }
}

这段代码会输出每个元素的索引和值。

示例2:忽略索引

如果你不关心索引,可以使用下划线 _ 忽略它。

for _, fruit := range fruits {
    fmt.Println(fruit)
}

遍历映射(map)

示例3:遍历映射
package main

import "fmt"

func main() {
    ages := map[string]int{"Alice": 30, "Bob": 25, "Charlie": 35}
    for name, age := range ages {
        fmt.Printf("%s is %d years old.\n", name, age)
    }
}

这里,name 是键,age 是值。

示例4:仅遍历映射的键或值

如果你想只获取映射的键或值,可以再次使用下划线 _

for name := range ages {
    fmt.Println(name)
}
// 或
for _, age := range ages {
    fmt.Println(age)
}

遍历通道

示例5:遍历通道
package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)
	go func() {
		for i := 0; i < 5; i++ {
			ch <- i
			time.Sleep(time.Second)
		}
		close(ch)
	}()

	for v := range ch {
		fmt.Println("Received:", v)
	}
}

在这个例子中,range 用于从通道接收值,直到通道被关闭。