Go 编程实战系列(十七)
上一篇《Go 运算符详解》中,我们学习了算术运算符、比较运算符、逻辑运算符等内容。有了这些基础之后,就可以开始学习 Go 中最重要的流程控制语句之一:if 判断。
程序并不总是按照固定顺序执行。很多时候,我们需要根据不同条件决定执行不同代码。例如:
用户登录成功 → 进入系统
用户登录失败 → 提示错误
年龄 >= 18 → 允许访问
库存 > 0 → 可以购买
余额不足 → 支付失败
这些业务逻辑都需要使用条件判断。在 Go 中,最常用的条件判断就是:
if
本文将详细介绍 Go 中的 if、if else、else if、多条件判断、嵌套判断、初始化语句以及实际项目中的常见写法。
一、if 是什么?
if 的作用非常简单:
如果条件成立,就执行指定代码。
基本语法:
markdown
if 条件 {
执行代码
}
例如:
go
package main
import "fmt"
func main() {
age := 20
if age >= 18 {
fmt.Println("已经成年")
}
}
运行结果:
已经成年
因为:
age >= 18
结果为:
arduino
true
所以 {} 中的代码会执行。
如果:
go
age := 16
条件:
age >= 18
结果为 false,因此代码不会执行。
二、Go 的 if 不需要括号
很多语言的 if 条件需要括号,例如 Java:
scss
if (age >= 18) {
}
Go 不需要:
arduino
if age >= 18 {
fmt.Println("成年人")
}
虽然某些情况下加括号语法上并非完全不可出现,但按照 Go 的代码风格,普通条件判断不要写没有必要的括号。
推荐:
if age >= 18 {
}
而不是:
scss
if (age >= 18) {
}
三、if 条件必须是 bool
Go 是强类型语言,if 后面的条件必须得到 bool 类型。
例如:
go
age := 20
if age > 18 {
fmt.Println("条件成立")
}
这里:
age > 18
结果是:
arduino
true
因此可以作为 if 条件。
但是不能写:
arduino
if 1 {
fmt.Println("执行")
}
也不能:
arduino
if "hello" {
}
Go 不会像某些语言一样把:
1
非空字符串
非零数字
自动认为是 true。
必须明确写出条件:
if count > 0 {
}
四、if else
如果希望条件成立执行一段代码,不成立执行另一段代码,可以使用:
arduino
if 条件 {
条件成立
} else {
条件不成立
}
例如:
go
package main
import "fmt"
func main() {
age := 16
if age >= 18 {
fmt.Println("成年人")
} else {
fmt.Println("未成年人")
}
}
输出:
未成年人
执行流程:
arduino
age >= 18
↓
是否成立
↓ ↓
true false
↓ ↓
成年人 未成年人
五、else if 多条件判断
实际业务往往不只有两种情况。
例如根据考试成绩划分等级:
90分以上 → 优秀
80~89 → 良好
60~79 → 及格
60以下 → 不及格
可以使用:
go
score := 85
if score >= 90 {
fmt.Println("优秀")
} else if score >= 80 {
fmt.Println("良好")
} else if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
输出:
良好
Go 会从上到下依次判断,一旦某个条件成立,后面的分支就不会继续执行。
因此条件顺序非常重要。
六、条件顺序问题
例如:
go
score := 95
if score >= 60 {
fmt.Println("及格")
} else if score >= 90 {
fmt.Println("优秀")
}
输出:
及格
虽然 95 分应该属于优秀,但:
score >= 60
已经成立,因此后面的:
score >= 90
不会再执行。
正确写法应该从更严格的条件开始:
arduino
if score >= 90 {
fmt.Println("优秀")
} else if score >= 60 {
fmt.Println("及格")
}
七、使用 && 判断多个条件
上一篇学习过逻辑运算符:
&&
表示"并且"。
例如登录判断:
go
usernameOK := true
passwordOK := true
if usernameOK && passwordOK {
fmt.Println("登录成功")
}
只有:
用户名正确
并且
密码正确
两个条件同时成立,才会登录成功。
实际案例:
go
age := 20
hasIDCard := true
if age >= 18 && hasIDCard {
fmt.Println("允许进入")
}
八、使用 || 判断多个条件
|| 表示"或者"。
例如后台权限:
go
isAdmin := false
isManager := true
if isAdmin || isManager {
fmt.Println("允许访问后台")
}
只要:
管理员
或者
经理
任意一个条件成立,就允许访问。
九、使用 ! 取反
! 表示逻辑取反。
例如:
go
isLogin := false
if !isLogin {
fmt.Println("请先登录")
}
因为:
ini
isLogin = false
那么:
diff
!isLogin
就是:
arduino
true
因此输出:
请先登录
这种写法在 Go 项目中非常常见。
十、if 嵌套
if 中还可以继续使用 if。
例如:
go
isLogin := true
isAdmin := true
if isLogin {
fmt.Println("用户已经登录")
if isAdmin {
fmt.Println("当前用户是管理员")
}
}
输出:
用户已经登录
当前用户是管理员
这种结构叫:
嵌套 if
但是不建议嵌套层级过深。
例如:
css
if a {
if b {
if c {
if d {
}
}
}
代码会越来越难阅读。
实际项目中应该尽量减少深层嵌套。
十一、使用提前 return 减少嵌套
假设有一个用户登录函数:
go
func login(username string, password string) {
if username != "" {
if password != "" {
fmt.Println("开始登录")
}
}
}
可以改成:
go
func login(username string, password string) {
if username == "" {
return
}
if password == "" {
return
}
fmt.Println("开始登录")
}
这种方式在 Go 项目中非常常见。
它通常被称为:
sql
Early Return
也就是提前返回。
优点:
-
减少嵌套;
-
主流程更加清晰;
-
错误条件优先处理;
-
更容易维护。
十二、if 可以带初始化语句
Go 的 if 有一个很有特点的语法:
ini
if 初始化语句; 条件 {
}
例如:
go
if age := 20; age >= 18 {
fmt.Println("成年人")
}
这里:
go
age := 20
先执行初始化。
然后判断:
age >= 18
结果成立后执行代码。
这种写法在 Go 项目中非常常见。
十三、if 初始化变量的作用域
例如:
css
if age := 20; age >= 18 {
fmt.Println(age)
}
这里的:
age
只能在这个 if 相关作用域中使用。
下面这样写:
scss
fmt.Println(age)
会报错,因为离开 if 后,age 已经不存在于当前作用域。
这种设计可以减少临时变量污染。
十四、if 与错误处理
Go 项目中最常见的 if 写法之一就是:
go
if err != nil {
return err
}
例如:
go
num, err := strconv.Atoi("100")
if err != nil {
fmt.Println("转换失败")
return
}
fmt.Println(num)
如果转换失败:
go
err != nil
就立即处理错误。
如果没有错误,则继续执行后面的代码。
这种模式在 Go 中会大量出现:
go
result, err := doSomething()
if err != nil {
return err
}
学习 Go 时一定要熟悉这种结构。
十五、Map 中的 if 判断
以后学习 Map 时,经常会看到:
css
value, ok := data["name"]
if ok {
fmt.Println(value)
}
还可以写成:
css
if value, ok := data["name"]; ok {
fmt.Println(value)
}
这样变量:
value
ok
只在当前判断中使用,代码更加紧凑。
十六、实际案例:年龄判断
go
package main
import "fmt"
func main() {
age := 20
if age < 0 {
fmt.Println("年龄数据错误")
} else if age < 18 {
fmt.Println("未成年人")
} else if age < 60 {
fmt.Println("成年人")
} else {
fmt.Println("老年人")
}
}
输出:
成年人
十七、实际案例:用户登录
go
package main
import "fmt"
func main() {
username := "admin"
password := "123456"
if username == "" {
fmt.Println("用户名不能为空")
return
}
if password == "" {
fmt.Println("密码不能为空")
return
}
if username == "admin" && password == "123456" {
fmt.Println("登录成功")
} else {
fmt.Println("用户名或密码错误")
}
}
这个案例已经非常接近真实业务程序的判断逻辑。
十八、实际案例:订单判断
假设购买商品需要满足:
商品已上架
库存充足
购买数量大于0
代码:
go
enabled := true
stock := 10
buyCount := 3
if !enabled {
fmt.Println("商品已经下架")
return
}
if buyCount <= 0 {
fmt.Println("购买数量错误")
return
}
if stock < buyCount {
fmt.Println("库存不足")
return
}
fmt.Println("可以购买")
这种写法比全部嵌套更加清晰。
十九、实际案例:判断奇偶数
dart
num := 11
if num%2 == 0 {
fmt.Println("偶数")
} else {
fmt.Println("奇数")
}
输出:
奇数
这里综合使用了:
markdown
%
==
if
else
二十、复杂条件建议使用变量
例如:
scss
if age >= 18 && age <= 60 && isLogin && !disabled && hasPermission {
fmt.Println("允许操作")
}
条件太长时,可读性会下降。
可以拆开:
go
validAge := age >= 18 && age <= 60
validUser := isLogin && !disabled
canAccess := validAge && validUser && hasPermission
if canAccess {
fmt.Println("允许操作")
}
这样更加容易理解和调试。
二十一、常见错误
1. 使用 = 代替 ==
错误:
ini
if age = 18 {
}
比较应该使用:
ini
if age == 18 {
}
= 是赋值,== 才是比较。
2. 使用数字作为条件
错误:
if 1 {
}
正确:
if count > 0 {
}
Go 的 if 条件必须是 bool。
3. else 换行位置错误
Go 中推荐并且通常必须这样写:
arduino
if age >= 18 {
fmt.Println("成年")
} else {
fmt.Println("未成年")
}
不要写成:
arduino
if age >= 18 {
fmt.Println("成年")
}
else {
fmt.Println("未成年")
}
因为 Go 的自动分号规则会导致语法问题。
4. 嵌套过深
不推荐:
css
if a {
if b {
if c {
if d {
}
}
}
}
优先考虑:
kotlin
if !a {
return
}
if !b {
return
}
if !c {
return
}
if !d {
return
}
让真正的业务逻辑保持在较浅层级。
二十二、if 最佳实践
实际 Go 项目中,可以遵循几个简单原则。
第一,优先处理错误:
go
if err != nil {
return err
}
第二,优先处理异常情况:
go
if user == nil {
return
}
第三,减少无意义的 bool 比较。
不推荐:
ini
if isLogin == true {
}
推荐:
if isLogin {
}
不推荐:
ini
if isLogin == false {
}
推荐:
yaml
if !isLogin {
}
第四,复杂条件拆成有意义的变量,让代码表达业务含义,而不仅仅是一堆运算符。
二十三、完整案例
go
package main
import "fmt"
func checkUser(
age int,
isLogin bool,
disabled bool,
) {
if age < 18 {
fmt.Println("年龄不足")
return
}
if !isLogin {
fmt.Println("请先登录")
return
}
if disabled {
fmt.Println("账号已被禁用")
return
}
fmt.Println("验证通过")
}
func main() {
checkUser(
20,
true,
false,
)
}
输出:
验证通过
这个案例体现了 Go 中非常常见的代码风格:
检查错误
↓
提前返回
↓
继续检查
↓
进入正常业务
随着项目越来越复杂,这种写法会比大量嵌套更加容易维护。
二十四、本章小结
本篇详细介绍了 Go 中的 if 条件判断,重点包括:
kotlin
if
if else
else if
&&
||
!
嵌套 if
if 初始化语句
变量作用域
提前 return
需要重点掌握以下几点:
if条件必须是 bool;- Go 的 if 条件不需要括号;
else if可以处理多个条件;- 多条件可以使用
&&和||; !可以对 bool 取反;- if 可以包含初始化语句;
- Go 项目中经常使用
if err != nil处理错误; - 尽量使用提前 return 减少代码嵌套。
掌握 if 后,我们已经可以根据不同条件控制程序执行不同的业务逻辑。但如果需要判断大量固定值,连续编写很多 else if 就会显得比较繁琐。
这时就可以使用 Go 提供的另一种流程控制语句:switch。
本章练习
- 输入年龄,判断用户是否成年。
- 输入成绩,根据分数输出优秀、良好、及格或不及格。
- 判断一个数字是奇数还是偶数。
- 使用
&&判断用户名和密码是否同时正确。 - 使用
||判断用户是否拥有管理员或经理权限。 - 编写商品购买判断:商品必须上架、库存必须充足。
- 使用提前 return 重写一个三层嵌套 if。
- 使用
if err != nil处理strconv.Atoi的转换错误。
下一篇预告
《Go switch 详解》
下一篇将继续学习 Go 流程控制中的 switch,包括:
-
switch 基本语法;
-
case 分支;
-
default;
-
一个 case 匹配多个值;
-
switch 表达式;
-
无表达式 switch;
-
fallthrough;
-
switch 与 if 的区别;
-
类型 switch;
-
实际业务中的状态判断案例。
当判断条件越来越多时,合理使用 switch 可以让 Go 代码更加清晰、简洁。