Go 多路条件语句 Switch 语法详解

Switch 是 Go 语言中一种多路条件语句,一般搭配 case 语句使用。

执行逻辑

一个 switch case 条件结构如下所示:

switch simpleStatement; condition {
	case expression1,expression2:
		statements
	case expression3:
		statements
	default:
		statements
	}

和 if 语句类似,switch 语句也可以在条件语句之前执行一段简短的表达式(可以用于很方便的控制变量的作用域),switch case 开始执行时,会先执行这一个表达式(空也算一种),然后计算出条件语句的值,接着按从上到下,从左到右的顺序一个一个的执行 case 语句的条件表达式,如果值相等的话就会进入执行 case 条件下对应的语句。 如果所有的 case 条件都没有能匹配上的话,然后就会尝试执行 default 下对应的逻辑。

case 条件合并

如果有时候多个 case 条件对应的处理逻辑是一样的话,Go 语言中的 case 条件是可以合并的,多个条件用逗号分隔,判断顺序是从左到右。

func main()  {
	switch runtime.GOOS {
	case "linux","darwin" :
		println("unix环境")
	case "windows":
		println("windows环境")
	}
}

支持的类型

不像 Java 只支持整型进行判断(其他类型都是通过转化成整型实现的),Go 里的 switch 的参数是一个表达式,支持任何类型进行比较,甚至 switch 的条件还可以是一个空的,这个时候等价于 switch true,可以用于简化多个 if 条件的场景。

func price(weight int) int  {
	if weight > 10 {
		return 100
	} else if weight > 8 {
		return 110
	} else if weight > 5 {
		return 120
	} else {
		return 150
	}
}

比如上方这个多重 if else 判断逻辑就可以用下方这个无参数的 switch case 语句替代:

func price(weight int) int  {
	switch  {
	case weight>10:
		return 100
	case weight>8:
		return 110
	case weight>5:
		return 120
	default:
		return 150
	}
}

隐式 break & fallthrough

Go 语言中匹配到一个 case 条件执行完对应的逻辑之后就会跳出这个 switch 语句,等价于每个 case 处理逻辑之后都加了一个隐式的 break 语句。如果不想要隐式退出的话可以使用 fallthrough 语句来继续下一个 case 的处理逻辑。 隐式 break:

func main()  {
	switch runtime.GOOS {
	case "linux","darwin" :
		println("unix环境")
	case "windows":
		println("window环境")
	default:
		println("什么都不是")
	}
}

输出:

windows环境

强行 fallthrough:

func main()  {
	switch runtime.GOOS {
	case "linux","darwin" :
		println("unix环境")
		fallthrough
	case "windows":
		println("windows环境")
		fallthrough // 会继续执行下一个语句
	default:
		println("什么都不是")
	}
}

输出:

windows环境
什么都不是

不过这一点就和很多其他编程语言正好相反,比如:Java、C++。Java 和 C++ 中的 switch case 都是隐式 fallthrough,而break 则需要显示调用,这两种方式各有利弊吧,还是看不同的使用场景,不过 Java 12 中也加入了对于隐式 break 的支持。 另外 Go 语言中也是可以显示调用 break 提前跳出的,用法和循环语句中的 break 是一样的,也可以加标签指定跳出具体哪一段逻辑。 break 显式跳出:

func main() {
	x := []int{1,2,3,4,5}
	for _, i := range x {
		switch  {
		case i>0 :
			if i > 1 && i < 3 {
				break
			}
			println(i)
		}
	}
}

输出:

1
3
4
5

指定标签跳出 for 循环:

func main() {
	x := []int{1,2,3,4,5}
	a:
	for _, i := range x {
		switch  {
		case i>0 :
			if i > 1 && i < 3 {
				break a
			}
			println(i)
		}
	}
}

输出:

1

Type Switch

Go 语言中的 switch 条件还可以是一种类型,这个特性在一个变量可能是多种类型时非常有用,虽然也可以 if else 加上类型断言来实现:

func main() {
	i := interface{}(123)
	if _,ok := i.(int);ok{
		println("int")
	}else if _,ok := i.(int64);ok {
		println("int64")
	}else if _,ok := i.(string);ok {
		println("string")
	}
}

但是用 Type Switch 的话代码会更简洁一些,比如上面的逻辑用 Type Switch 重写:

func main() {
	i := interface{}(123)
	switch i.(type) {
	case int:
		println("int")
	case int64:
		println("int64")
	case float64:
		println("float64")
	}
}

输出:

int

(注:这里 123 是 int 类型而不是 int64,因为在申明变量时并没有指定具体类型,编译器会自行推导类型,而 int 是无类型整形的默认类型。) 同时 Type Switch 可以给赋值给一个变量,这个变量在不同的 case 中会变成对应 case 条件的类型(在合并了 case 语句之后会失效)

func main() {
	var i interface{}
	switch x := i.(type) {
	case error:
		x.Error()
	case fmt.Stringer:
		x.String()
	}
}