【Golang开发】快速入门Go——控制语句和函数

引言

在掌握 Go 语言的数据类型与变量基础后,我们的学习将进入 "程序逻辑构建" 的核心阶段 ------ 函数是代码复用与逻辑封装的核心载体,而控制语句则是梳理函数执行流程的关键工具。

通过这篇文章,你将系统掌握 Go 语言中两类核心语法的应用:

  • 控制语句的核心用法(含条件判断、循环遍历、流程跳转),为构建清晰的程序逻辑流打下基础;
  • 函数的定义规范、参数传递与实际调用方式,学会用函数封装可复用的代码块。

控制语句

条件语句

if 语句

基本语法

go 复制代码
// 形式1:基础条件
if 条件表达式 {
    // 条件为true时执行
}

// 形式2:带初始化语句(常用,变量作用域仅限if块)
if 初始化语句; 条件表达式 {
    // 条件为true时执行
} else if 其他条件 {
    // 其他条件为true时执行
} else {
    // 所有条件为false时执行
}

特点

  • 条件表达式无需用括号 () 包裹,但必须有大括号 {} (即使只有一行代码);
  • 初始化语句(如 a := 10)声明的变量,作用域仅限 if-else 块内;
  • 支持多分支 else if,但不支持 else if 换行(必须紧跟前一个块的 })。

示例

go 复制代码
// 带初始化语句的if
if score := 85; score >= 90 {
    fmt.Println("优秀")
} else if score >= 60 {
    fmt.Println("及格") // 输出:及格
} else {
    fmt.Println("不及格")
}

switch 语句

基本语法

go 复制代码
// 形式1:带条件(判断条件表达式的值)
switch 条件表达式 {
case 可能值1:
    // 条件等于可能值1时执行
case 可能值2, 可能值3: // 多个值用逗号分隔
    // 条件等于可能值2或3时执行
default:
    // 所有case不匹配时执行
}

// 形式2:不带条件(等价于switch true,可替代多分支if-else)
switch {
case 条件1:
    // 条件1为true时执行
case 条件2:
    // 条件2为true时执行
}

核心特性

  • 自动 break :执行完一个 case 后,默认自动跳出 switch(无需显式写 break);
  • case 支持表达式case 后可以是常量、变量或表达式(如 case a > 10),不要求必须是常量;
  • 类型判断 :可用于类型断言(switch v := x.(type)),判断接口变量的实际类型。
go 复制代码
// 基础用法
day := 3
switch day {
case 1:
    fmt.Println("周一")
case 2, 3:
    fmt.Println("周二或周三") // 输出:周二或周三
default:
    fmt.Println("其他")
}

// 不带条件的switch(替代多if-else)
score := 75
switch {
case score >= 90:
    fmt.Println("优秀")
case score >= 60:
    fmt.Println("及格") // 输出:及格
}

// 类型断言(判断接口类型)
var x interface{} = "hello"
switch v := x.(type) {
case int:
    fmt.Println("int类型,值为", v)
case string:
    fmt.Println("string类型,值为", v) // 输出:string类型,值为 hello
}

循环语句

Go 语言只有一种循环语句 for,但通过不同形式可实现其他语言中 whiledo-while 的功能,同时支持 for range 遍历集合。

for 循环的三种形式

  1. 类 C 风格(初始化;条件;增量)
go 复制代码
for i := 0; i < 5; i++ {
    fmt.Println(i) // 输出:0,1,2,3,4
}
  1. 类 while 风格(仅条件)
go 复制代码
i := 0
for i < 5 { // 等价于while(i < 5)
    fmt.Println(i)
    i++
}
  1. 无限循环(无条件)
go 复制代码
i := 0
for { // 等价于while(true)
    if i >= 5 {
        break // 退出循环
    }
    fmt.Println(i)
    i++
}

for range:遍历集合元素

for range 是 Go 特有的遍历方式,用于便捷遍历数组、切片、字符串、映射(map)、通道(channel)等集合类型。

go 复制代码
for 索引/键, 值 := range 集合 {
    // 循环体
}

不同集合的遍历特点:

  • 数组 / 切片:range 返回 "索引" 和 "对应值"(值是元素的副本,修改不影响原集合);
  • 字符串:range 返回 "字节索引" 和 "Unicode 字符"(自动处理多字节字符,如中文);
  • 映射(map):range 返回 "键" 和 "值"(遍历顺序随机,每次可能不同);
  • 通道(channel):range 会持续接收通道数据,直到通道关闭(常用于消费协程数据)。

跳转语句

包括breakcontinuegoto三种:

break:跳出当前循环或 switch

  • 在循环中,默认跳出最内层循环;
  • 可配合标签(label) 跳出指定的外层循环(解决多层循环跳出问题)。
go 复制代码
// 基础用法:跳出单层循环
for i := 0; i < 5; i++ {
    if i == 3 {
        break // i=3时跳出循环
    }
    fmt.Println(i) // 输出:0,1,2
}

// 带标签:跳出外层循环
outer: // 定义外层循环标签
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        if i == 1 && j == 1 {
            break outer // 跳出outer标签对应的外层循环
        }
        fmt.Printf("i=%d,j=%d\n", i, j)
    }
}
// 输出:i=0,j=0 i=0,j=1 i=0,j=2 i=1,j=0

continue:跳过当前循环的剩余部分

  • 默认作用于最内层循环;
  • 可配合标签,跳过指定外层循环的当前迭代。
go 复制代码
// 基础用法:跳过当前迭代
for i := 0; i < 5; i++ {
    if i == 2 {
        continue // i=2时跳过后续打印,进入下一次循环
    }
    fmt.Println(i) // 输出:0,1,3,4
}

// 带标签:跳过外层循环的当前迭代
outer:
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        if j == 1 {
            continue outer // 跳过外层循环的当前迭代(i不变,直接i++)
        }
        fmt.Printf("i=%d,j=%d\n", i, j)
    }
}
// 输出:i=0,j=0 i=1,j=0 i=2,j=0

goto:跳转到函数内的标签

  • goto 用于直接跳转到同一函数内的指定标签(label) ,实现代码跳转。
  • 标签必须在当前函数内,且是一个独立的代码块(如 label: 后需有语句或大括号);
  • 谨慎使用:过度使用会导致代码逻辑混乱,建议仅在简化多层嵌套退出时使用(如替代多层 break)。
go 复制代码
// 用goto简化多层条件退出
func check() {
    if err := step1(); err != nil {
        goto fail // 步骤1出错,跳转到fail标签
    }
    if err := step2(); err != nil {
        goto fail // 步骤2出错,跳转到fail标签
    }
    fmt.Println("所有步骤成功")
    return

fail: // 标签定义
    fmt.Println("执行失败")
}

函数

函数的基本结构

Go 中函数的定义格式如下,核心由 func 关键字、函数名、参数列表、返回值类型和函数体组成:

go 复制代码
func 函数名(参数列表) (返回值类型列表) { 
    // 函数体(执行逻辑) 
}
  • func:声明函数的关键字(固定)
  • 函数名:遵循 Go 命名规范(首字母大写可导出,小写仅包内可见)
  • 参数列表:格式为 参数名 类型,多个参数用逗号分隔(如 a int, b string);若连续参数类型相同,可合并(如a, b int
  • 返回值类型列表:单个返回值可直接写类型(如 int);多个返回值需用括号包裹(如 (int, error)
  • 函数体:包含具体执行逻辑的代码块(用 {} 包裹),注意左括号需要和函数名在同一行,不然编译会错

如何创建函数

根据参数和返回值的不同,函数可分为多种类型,以下是常见场景示例:

无参数、无返回值的函数

go 复制代码
// 定义一个打印欢迎信息的函数
func printWelcome() {
    fmt.Println("Welcome to Go!")
}

有参数、无返回值的函数

接收参数并处理,但不返回结果(参数是 "值传递",函数内修改不影响外部):

go 复制代码
// 定义一个打印整数的函数,接收一个int类型参数num
func printNumber(num int) {
    fmt.Printf("The number is: %d\n", num)
}

// 多个参数的函数(参数类型相同时,可简写为 "a, b int")
func printSum(a, b int) {
    fmt.Printf("%d + %d = %d\n", a, b, a+b)
}

有参数、有返回值的函数

接收参数并返回处理结果,支持单个或多个返回值(Go 的特色):

(1)单个返回值

go 复制代码
// 定义一个加法函数,接收两个int参数,返回它们的和(int类型)
func add(a, b int) int {
    return a + b // 用return返回结果
}

(2)多个返回值(常用场景:返回结果 + 错误信息)

go 复制代码
// 定义一个除法函数,返回商和余数(两个int)
func divide(dividend, divisor int) (int, int) {
    quotient := dividend / divisor  // 商
    remainder := dividend % divisor // 余数
    return quotient, remainder      // 用逗号分隔多个返回值
}

// 带错误返回的函数(Go中处理错误的标准方式)
func safeDivide(dividend, divisor int) (int, error) {
    if divisor == 0 {
        // 返回错误信息(需导入"errors"包)
        return 0, errors.New("divisor cannot be zero")
    }
    return dividend / divisor, nil // 成功时错误为nil
}

命名返回值函数

可以给返回值提前命名(类似函数内的变量),简化 return 语句(直接 return 即可返回当前值):

go 复制代码
// 命名返回值:sum和product是返回值的名称
func calculate(a, b int) (sum int, product int) {
    sum = a + b      // 直接给命名返回值赋值
    product = a * b
    return           // 无需显式写返回值,自动返回sum和product
}

可变参数函数

参数数量不固定(类似数组),用 ... 表示,必须是参数列表的最后一个:

go 复制代码
// 计算任意个整数的和(nums是一个[]int类型的切片)
func sumAll(nums ...int) int {
    total := 0
    for _, num := range nums { // 遍历可变参数(本质是切片)
        total += num
    }
    return total
}

如何调用函数

函数定义后,通过 "函数名 + 参数列表" 的方式调用,根据返回值情况决定是否接收结果。

调用无返回值的函数

直接写函数名和参数(如果有):

go 复制代码
func main() {
    printWelcome()          // 调用无参数函数:输出 "Welcome to Go!"
    printNumber(100)        // 调用单参数函数:输出 "The number is: 100"
    printSum(3, 5)          // 调用多参数函数:输出 "3 + 5 = 8"
}

调用有返回值的函数

用变量接收返回值(数量需与函数定义的返回值数量一致):

go 复制代码
func main() {
    // 调用单个返回值的函数
    result := add(2, 3)
    fmt.Println("2 + 3 =", result) // 输出:2 + 3 = 5

    // 调用多个返回值的函数(用逗号分隔变量)
    quot, rem := divide(10, 3)
    fmt.Println("10 ÷ 3 =", quot, "余", rem) // 输出:10 ÷ 3 = 3 余 1

    // 调用带错误的函数(常用模式:先判断错误)
    divResult, err := safeDivide(10, 0)
    if err != nil { // 错误不为nil时,处理错误
        fmt.Println("Error:", err) // 输出:Error: divisor cannot be zero
    } else {
        fmt.Println("Result:", divResult)
    }

    // 忽略某个返回值(用空白标识符_)
    justQuot, _ := divide(10, 3) // 只关心商,忽略余数
    fmt.Println("商:", justQuot)
}

调用可变参数函数

传递任意数量的参数(或直接传递切片,需在切片后加 ...):

go 复制代码
func main() {
    // 直接传递多个参数
    total1 := sumAll(1, 2, 3, 4)
    fmt.Println("总和:", total1) // 输出:总和:10

    // 传递切片(需加...)
    nums := []int{5, 6, 7}
    total2 := sumAll(nums...) // 等价于 sumAll(5,6,7)
    fmt.Println("总和:", total2) // 输出:总和:18
}

函数的可见性

  • 函数名首字母大写 :可被其他包调用(导出函数),如 fmt.Println()Println 首字母大写)。
  • 函数名首字母小写 :仅能在当前包内调用(非导出函数),如上面的 add 函数若改为 add(小写),其他包无法访问。

特殊函数

类似于C++,可执行程序的入口函数是main函数 ,有固定格式:

  • 必须定义在 main 包中(package main)。
  • 无参数、无返回值(func main())。
  • 程序启动时自动调用 main 函数。
go 复制代码
package main // 必须声明为main包

import "fmt"

func main() { // 入口函数
    fmt.Println("程序开始执行")
    // 其他函数调用放在这里
}

总结

本文围绕 Go 语言 "程序逻辑构建" 的核心目标展开,系统讲解了支撑代码逻辑与封装的两大关键语法 ------ 控制语句与函数。

控制语句是 "梳理函数内部逻辑的骨架",函数是 "承载控制语句、实现逻辑复用的容器",二者相辅相成。掌握这两类语法,不仅完成了从 "基础语法认知" 到 "核心逻辑构建" 的过渡,更为后续学习 Go 语言的并发编程、项目开发等进阶内容,打下了坚实的结构化代码基础。

相关推荐
自由的疯1 小时前
Java RuoYi整合Magic-Api详解
java·后端·架构
自由的疯1 小时前
Java 实现TXT文件上传并解析的Spring Boot应用
后端·架构
开始学java2 小时前
抽象类和抽象方法
后端
华仔啊2 小时前
别再乱 new ArrayList!8 大 Java 容器选型案例,一篇看懂
java·后端
小码编匠2 小时前
手把手教会设计 WinForm 高DPI兼容程序,告别字体模糊与控件乱飞(.NET 4.6.1/.NET 6.0)
后端·c#·.net
秋难降3 小时前
MySQL 优化:告别 “996”,让系统高效运行
数据库·后端·mysql
追逐时光者3 小时前
很强!一款基于 .NET 构建、功能强大、通用的 2D 图形编辑器
后端·.net
mzlogin4 小时前
Java|FreeMarker 复用 layout
java·后端·freemarker
MrHuang9654 小时前
【创建线程的四种方式】
后端
双向334 小时前
Python 多线程日志错乱:logging.Handler 的并发问题
后端