引言
在掌握 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
,但通过不同形式可实现其他语言中 while
、do-while
的功能,同时支持 for range
遍历集合。
for
循环的三种形式
- 类 C 风格(初始化;条件;增量)
go
for i := 0; i < 5; i++ {
fmt.Println(i) // 输出:0,1,2,3,4
}
- 类 while 风格(仅条件)
go
i := 0
for i < 5 { // 等价于while(i < 5)
fmt.Println(i)
i++
}
- 无限循环(无条件)
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
会持续接收通道数据,直到通道关闭(常用于消费协程数据)。
跳转语句
包括break
、continue
、goto
三种:
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 语言的并发编程、项目开发等进阶内容,打下了坚实的结构化代码基础。