Go 条件语句:if 与 switch

程序不可能永远直线走,经常要"看情况办事"——条件语句就是用来做分支选择的。Go 主要有 if/elseswitch 两种,语法上比 C/Java 更简洁,也有几个自己的小规矩。本篇带你逐一掌握,并顺带认识 Go 独特的 Type Switch。

一、if 语句

Go 的 if 有两个明显特点:条件不用加括号,但花括号必须写——哪怕后面只有一行代码也不能省。而且左花括号 { 必须和 if 写在同一行,不能另起一行,否则编译直接报错(这是 Go 强制代码风格的体现)。

package main

import "fmt"

func main() {
    score := 85
    if score >= 90 {
        fmt.Println("优秀")
    } else if score >= 60 {
        fmt.Println("及格")
    } else {
        fmt.Println("不及格")
    }
}

二、if 的初始化语句

Go 的 if 可以在条件前先执行一条初始化语句,中间用分号隔开。这非常适合"先算个值,再判断它"的场景,而且这个临时变量的作用域只在 if/else 块内,出了块就消失,保持外部命名空间干净。

package main

import "fmt"

func compute() int {
    return 42
}

func main() {
    // if 可以带一条初始化语句,用分号与条件隔开
    if v := compute(); v > 100 {
        fmt.Println("太大:", v)
    } else {
        fmt.Println("OK:", v) // v 在 else 分支里依然可用
    }
    // fmt.Println(v) // 编译错误:v 的作用域仅限于 if/else 块内
}

这种写法在 Go 里到处可见,最典型的就是错误处理范式: if err := doSomething(); err != nil { ... }。先调用函数拿到 err,紧接着判断它是否为空,一行搞定,而且 err 不会污染外层作用域。

三、switch 语句

当一个变量要和很多种值比较时,写一长串 if/else if 会很丑,switch 更清晰。Go 的 switch 和 C/Java 有几个关键不同:

package main

import "fmt"

func main() {
    day := "Sat"
    switch day {
    case "Sat", "Sun": // 一个 case 匹配多个值,逗号分隔
        fmt.Println("周末")
    case "Mon", "Tue", "Wed", "Thu", "Fri":
        fmt.Println("工作日")
    default:
        fmt.Println("未知")
    }
}

四、无条件 switch 与 fallthrough

switch 还可以不写表达式,把判断条件放在每个 case 里——相当于把 if/else 链换了一种排版,分支多时更整齐。配合 fallthrough 则可以强制"穿透"到下一个 case 的代码体(注意:fallthrough 不检查下个 case 的条件,无条件进入,而且只穿透一层)。

package main

import "fmt"

func main() {
    // 1. 无条件 switch:省略表达式,等价于 if/else 链
    n := -5
    switch {
    case n < 0:
        fmt.Println("负数")
    case n == 0:
        fmt.Println("零")
    default:
        fmt.Println("正数")
    }

    // 2. fallthrough:强制进入下一个 case 的代码体(不检查条件)
    x := 1
    switch x {
    case 1:
        fmt.Println("一")
        fallthrough
    case 2:
        fmt.Println("二") // 即使 x != 2,这里也会执行
    }
}

五、Type Switch(类型判断)

这是 Go 比较独特的一个用法。Go 的接口(interface)内部存着一个"动态类型",想在运行时知道它到底是什么类型,就用类型 switch。语法是 switch v := x.(type) { ... },每个 case 匹配一种类型,并且 v 在对应分支里会自动成为那种类型,用起来非常顺手。

package main

import "fmt"

// describe 接收任意类型的参数(空接口 interface{})
func describe(i interface{}) {
    // 类型 switch:判断接口里实际存放的动态类型
    switch v := i.(type) {
    case int:
        fmt.Println("整数,值 =", v)
    case string:
        fmt.Printf("字符串,长度 = %d\n", len(v))
    case bool:
        fmt.Println("布尔:", v)
    default:
        fmt.Printf("其它类型:%T\n", v)
    }
}

func main() {
    describe(42)
    describe("hello")
    describe(true)
    describe(3.14)
}

这在处理泛化数据(JSON 解析、通用容器、第三方库返回值)时非常有用,让你安全地对接口值做"类型分发"。除了 type switch,还有单值类型断言 v, ok := x.(int),ok 用来标识断言是否成功。

六、select 简单提及

除了 ifswitch,Go 还有一个 select 语句,长得像 switch,但专门用于多个 channel 的选择——哪个 channel 先准备好就执行哪个分支。它是并发编程的核心控制结构,要等学到 channel 和 goroutine 时才能完全理解,这里先有个印象即可,暂不展开。

小结

if 条件不加括号、花括号必写、可带初始化语句;switch 默认不穿透、支持多值匹配和无条件写法;Type switch 用于判断接口的动态类型;select 留给并发。下一篇进入 Go 唯一的循环——for

上一篇 Go 运算符 | 下一篇 Go 循环

✈️💬