Go语言判断语句
Go语言判断语句
判断语句是程序控制流的基础。Go提供了 if 和 switch 两种判断结构,语法上与C/Java有不少差异——不需要括号、默认不穿透、支持初始化语句等。本文将系统介绍Go判断语句的写法、逻辑运算符、以及与Java的对比。
if 语句
基本语法
Go的 if 不需要小括号包裹条件,但花括号是必须的:
age := 20 |
注意:左花括号 { 必须与 if/else 在同一行,不能换行。这是Go编译器的强制要求,不是风格偏好:
// 编译错误 |
原因是Go在编译时会自动在行尾插入分号。如果 { 换行,编译器会在 if age >= 18 后面插入分号,导致语法错误。
if 初始化语句
Go的 if 支持在条件前加一条初始化语句,用分号分隔。初始化语句中声明的变量作用域仅限于整个 if-else 块:
// 推荐写法:err 作用域限定在 if-else 块内 |
这种写法在Go中非常常见,尤其是错误处理和类型断言场景:
// 类型断言 |
逻辑运算符
Go提供三个逻辑运算符,与大多数语言一致:
| 运算符 | 含义 | 示例 |
|---|---|---|
&& |
逻辑与(AND) | a && b:a和b都为true时结果为true |
|| |
逻辑或(OR) | a || b:a或b有一个为true时结果为true |
! |
逻辑非(NOT) | !a:取反,true变false,false变true |
age := 25 |
优先级
! > && > ||,与数学中”非 > 与 > 或”一致。建议在复杂表达式中使用括号明确意图:
// 不加括号,依赖优先级 |
短路求值(Short-circuit Evaluation)
Go的逻辑运算符 && 和 || 采用短路求值——如果通过左侧表达式已经能确定结果,右侧表达式不会被执行。
&& 短路
&& 的左侧为 false 时,整个表达式必定为 false,右侧不再执行:
func isValid() bool { |
|| 短路
|| 的左侧为 true 时,整个表达式必定为 true,右侧不再执行:
x := 1 |
短路的实际应用
短路求值不只是性能优化,更是一种安全保护——可以避免空指针等运行时错误:
// 先判断 nil,再访问字段,避免 panic |
如果没有短路机制,上面的写法都会在条件不满足时触发 panic。
switch 语句
基本语法
day := "Monday" |
一个 case 匹配多个值
switch day { |
switch 初始化语句
与 if 一样,switch 也支持初始化语句:
switch today := time.Now().Weekday(); today { |
无表达式 switch
省略 switch 后面的表达式时,每个 case 可以是独立的条件表达式,相当于 if-else if-else 的替代写法:
score := 85 |
当分支超过3个时,无表达式 switch 比 if-else 链更清晰。
Type Switch(类型判断)
用于判断 interface{} 的具体类型,是Go独有的 switch 用法:
func describe(i interface{}) string { |
注意:i.(type) 语法只能在 switch 中使用,不能单独使用。单一类型判断用类型断言 v, ok := i.(int)。
fallthrough
Go的switch 默认不穿透,每个case执行完自动break。需要穿透时使用 fallthrough 关键字:
x := 1 |
fallthrough 的三条规则
1. 无条件跳入下一个 case 的代码体,不检查条件
switch 1 { |
2. 必须是 case 块的最后一条语句
switch x { |
3. 不能用在 type switch 中
switch v := i.(type) { |
实际开发中
fallthrough很少使用。大多数需要穿透的场景可以通过一个 case 匹配多个值来替代:case 1, 2, 3:。
Go与Java判断语句的对比
if 对比
| 特性 | Go | Java |
|---|---|---|
| 条件括号 | 不需要 if x > 0 {} |
必须 if (x > 0) {} |
| 花括号 | 必须,即使只有一行 | 单行可省略(不推荐) |
| 初始化语句 | 支持 if err := f(); err != nil {} |
不支持 |
| 条件类型 | 必须是 bool |
必须是 boolean |
| 隐式类型转换 | 不支持,if 1 {} 编译错误 |
不支持,if (1) {} 编译错误 |
Go和Java在这一点上一致:条件必须是布尔类型,不像C/JavaScript那样允许整数或对象做条件。
switch 对比
| 特性 | Go | Java |
|---|---|---|
| 默认行为 | 不穿透,自动break | 穿透,需要手动break |
| 穿透控制 | 需要 fallthrough 显式穿透 |
需要 break 显式停止 |
| case 值类型 | 任意表达式,可以不是常量 | Java 14之前需要常量(int/enum/String) |
| 多值匹配 | case 1, 2, 3: |
Java 14+ case 1, 2, 3 -> |
| 无表达式 switch | 支持 switch {} |
不支持 |
| type switch | 支持 switch v := i.(type) |
通过 instanceof + if-else 实现 |
| switch 表达式 | 不支持(switch是语句) | Java 14+ 支持 switch 表达式有返回值 |
典型代码对比
Go 风格:
switch day { |
Java 风格(传统):
switch (day) { |
Java 14+ 新语法:
switch (day) { |
Java 14+ 的箭头语法借鉴了Go的”默认不穿透”设计。
面试高频题
Q1:Go 的 if 和 Java 的 if 有什么区别?
答:主要有三点区别。第一,Go的 if 条件不需要小括号,但花括号是强制的,即使只有一行代码;Java 的 if 条件必须加小括号,单行代码可以省略花括号。第二,Go支持 if 初始化语句 if err := f(); err != nil {},Java 不支持。第三,两者的条件都必须是布尔类型,不支持隐式类型转换。
Q2:下面代码能编译通过吗?为什么?
x := 1 |
答:不能。Go不支持条件表达式的隐式类型转换,if 的条件必须是 bool 类型。整数 1 不是 bool,编译器报错 non-bool x (variable of type int) used as condition。必须写成 if x != 0 {}。
Q3:短路求值是什么?有什么实际作用?
答:短路求值是指 && 的左侧为 false 时右侧不执行,|| 的左侧为 true 时右侧不执行。除了减少不必要的计算外,最重要的作用是安全保护。例如 if p != nil && p.Name == "admin",如果没有短路机制,当 p 为 nil 时访问 p.Name 会触发 panic。短路保证了左侧条件不满足时,右侧不会执行。
Q4:Go 的 switch 为什么默认不穿透?
答:在C/Java中,switch 默认穿透、需要手动写 break 是大量 bug 的来源——忘记写 break 导致意外执行下一个 case 是非常常见的错误。Go的设计哲学是”让正确的写法成为默认行为”,所以默认不穿透。极少数需要穿透的场景,通过显式的 fallthrough 关键字实现,意图更清晰。
Q5:fallthrough 的行为是什么?它会重新判断下一个 case 的条件吗?
答:不会。fallthrough 是无条件跳入下一个 case 的代码体,不会重新评估下一个 case 的条件。例如 switch 1 中 case 1 使用了 fallthrough,即使下一个是 case 99(值不匹配),也会执行 case 99 的代码。另外,fallthrough 必须是 case 块的最后一条语句,且不能用在 type switch 中。
Q6:下面代码输出什么?
func check() bool { |
答:只输出 条件成立,不会输出 check 被调用。因为 || 短路求值——x > 5 为 true,整个表达式已经确定为 true,右侧 check() 不会被调用。
Q7:if 初始化语句中声明的变量,在 else 块中能访问吗?
if val, ok := m["key"]; ok { |
答:能。if 初始化语句中声明的变量,作用域是整个 if-else 链,包括 if、else if、else 所有分支。出了 if-else 块才不可见。这里 val 和 ok 在 else 块中都能访问,val 会是类型的零值。
Q8:type switch 和类型断言有什么区别?
答:类型断言 v, ok := i.(int) 用于判断单一类型,如果不使用 comma ok 模式(直接 v := i.(int)),类型不匹配时会 panic。Type switch switch v := i.(type) 可以同时匹配多种类型,不会 panic,匹配不到走 default。需要判断多种类型时用 type switch,判断单一类型时用类型断言的 comma ok 模式。此外,fallthrough 不能用在 type switch 中。
小结
| 概念 | 要点 |
|---|---|
| if 语法 | 条件不加括号,花括号必须,左花括号不能换行 |
| if 初始化语句 | if x := f(); x > 0 {},变量作用域限定在 if-else 块内 |
| 逻辑运算符 | ! > && > ` |
| 短路求值 | && 左侧为false则右侧不执行,` |
| switch 默认行为 | 自动break,不穿透 |
| fallthrough | 无条件进入下一个case的代码体,不重新判断条件,不可用于type switch |
| 无表达式 switch | switch {} 等价于 if-else 链,分支多时更清晰 |
| type switch | switch v := i.(type) 判断接口的具体类型 |
| Go vs Java | Go默认不穿透、不需要括号、支持初始化语句和type switch |
下一篇将介绍Go的循环语句(for)与跳转控制。











