Go 语言入门指南:基础语法和常用特性解析(下) | 青训营

72 阅读4分钟

在上篇中,我们介绍了Go语言的包和导入、数据类型和函数,这些是Go语言的基础。在本文中,我们将继续探索Go语言的一些重要特性,包括控制流、协程(Goroutine)等,通过代码示例来学习它们的用法和优势。

1. 控制流

控制流是指程序执行的顺序和分支。Go语言提供了三种基本的控制流结构:if-else、for和switch。

if-else

if-else是最常见的条件判断结构,它根据一个布尔表达式的值来执行不同的代码块。Go语言的if-else语句可以在条件之前执行一个简短的语句,例如赋值或函数调用,这样可以减少代码的重复和提高可读性。例如:

// 判断一个数是否为偶数  
func isEven(n int) bool {  
    if remainder := n % 2; remainder == 0 {  
        return true  
    } else {  
        return false  
    }  
}  

for

for是Go语言中唯一的循环结构,它可以用来重复执行一段代码,直到满足某个条件或者遍历一个集合。Go语言的for循环有三种形式:

  • 带有初始值、条件和步长的经典形式,类似于其他编程语言中的for循环。例如:
// 打印1到10之间的所有偶数  
for i := 1; i <= 10; i++ {  
// 如果i是偶数,打印i  
    if isEven(i) {  
        fmt.Println(i)  
    }  
}  
  • 只有条件的形式,类似于其他编程语言中的while循环。例如:
rand.Seed(time.Now().UnixNano()) // 设置随机数种子  
n := 0 // 初始化n为0  
for n != 50 { // 当n不等于50时循环  
    n = rand.Intn(100) + 1 // 生成一个1到100之间的随机数  
    fmt.Println(n) // 打印n  
}  
  • 没有条件的形式,类似于其他编程语言中的无限循环。这种形式需要在循环体内使用break或return来跳出循环。例如:
// 计算斐波那契数列的前10项,并打印它们  
a, b := 0, 1 
for {
    fmt.Println(a) 
    a, b = b, a+b // 更新a和b为b和a+b  
    if a > 100 { // 如果a大于100,跳出循环  
        break  
    }  
}  

另外,Go语言还提供了一个range关键字,可以用来遍历数组、切片、映射或通道等集合类型。range会返回每个元素的索引和值(或者键和值),可以使用_来忽略不需要的返回值。例如:

// 创建一个字符串数组  
names := []string{"Alice", "Bob", "Charlie", "David"}  
// 使用range遍历数组,并打印每个元素的索引和值  
for i, name := range names {  
    fmt.Printf("index: %d, name: %s\n", i, name)  
}  

switch

switch是一种多分支选择结构,它根据一个表达式的值来匹配不同的case,并执行相应的代码块。Go语言的switch语句有以下特点:

  • switch表达式的类型可以是任意的,不一定是整数或字符串。
  • case语句可以包含多个值,用逗号分隔,表示任意一个值都可以匹配。
  • case语句不需要使用break来结束,Go语言会自动跳出switch语句。
  • case语句可以使用fallthrough关键字来继续执行下一个case,而不是跳出switch语句。
  • switch语句可以没有表达式,相当于switch true,用来替代多个if-else语句。

例如:

// 根据月份打印季节  
month := time.Now().Month() // 获取当前月份  
switch month {  
case 12, 1, 2: // 如果是12月、1月或2月  
    fmt.Println("Winter") // 打印Winter  
case 3, 4, 5: // 如果是3月、4月或5月  
    fmt.Println("Spring") // 打印Spring  
case 6, 7, 8: // 如果是6月、7月或8月  
    fmt.Println("Summer") // 打印Summer  
case 9, 10, 11: // 如果是9月、10月或11月  
    fmt.Println("Autumn") // 打印Autumn  
default: // 其他情况  
    fmt.Println("Unknown") // 打印Unknown  
}  

2. 协程(Goroutine)

协程(Goroutine)是Go语言中实现并发编程的一种方式,它可以让一个程序中的多个任务同时运行,提高程序的效率和性能。Go语言的协程非常轻量,一个程序可以创建成千上万个协程,而不会消耗太多的系统资源。

要创建一个协程,只需要在一个函数调用前加上go关键字,就可以让这个函数在一个新的协程中执行。例如:

// 定义一个打印Hello World的函数  
func sayHello() {  
    fmt.Println("Hello World")  
}  
// 在主函数中创建一个协程来调用sayHello函数  
func main() {  
    go sayHello() // 在一个新的协程中执行sayHello函数  
    time.Sleep(time.Second) // 主函数暂停一秒钟,等待协程执行完毕  
}  

注意,主函数也是一个协程,当主函数结束时,所有其他的协程也会被终止。因此,我们需要使用time.Sleep或其他方式来等待其他协程执行完毕。

如果我们想让多个协程之间进行通信和同步,我们可以使用Go语言提供的一种特殊类型:通道(Channel)。通道是一种类似于队列的数据结构,可以让多个协程安全地发送和接收数据。要创建一个通道,我们可以使用make函数,并指定通道的数据类型。例如:

// 创建一个传递整数的通道  
ch := make(chan int)  

要向通道发送数据,我们可以使用<-运算符,并把通道放在右边。例如:

// 向通道ch发送一个整数0 
ch <- 0  

要从通道接收数据,我们也可以使用<-运算符,并把通道放在左边。例如:

// 从通道ch接收一个整数,并赋值给变量n  
n := <-ch  

通道的发送和接收操作都是阻塞的,也就是说,如果通道为空,接收操作会等待直到有数据可读;如果通道已满(有缓冲区时),发送操作会等待直到有空间可写。这样就可以实现协程之间的同步和互斥。