背景

go switch 在一些场景上面的介绍。
来源

switch

Go的switch语句非常简洁。首先,您不需要在每一种情况结束时中断。

switch c {
case '&':
	esc = "&"
case '\'':
	esc = "'"
case '<':
	esc = "&lt;"
case '>':
	esc = "&gt;"
case '"':
	esc = "&quot;"
default:
	panic("unrecognized escape character")
}

Not just integers 不是只有int类型

switch 作用于任何类型的值。

switch syscall.OS {
case "windows":
	sd = &sysDir{
		Getenv("SystemRoot") + `\system32\drivers\etc`,
		[]string{
			"hosts",
			"networks",
			"protocol",
			"services",
		},
	}
case "plan9":
	sd = &sysDir{
		"/lib/ndb",
		[]string{
			"common",
			"local",
		},
	}
default:
	sd = &sysDir{
		"/etc",
		[]string{
			"group",
			"hosts",
			"passwd",
		},
	}
}

Missing expression 表达式的问题

switch没有值表示“switch true”,使其成为if-else链的更简洁版本,如Effective Go的示例:

func unhex(c byte) byte {
	switch {
	case '0' <= c && c <= '9':
		return c - '0'
	case 'a' <= c && c <= 'f':
		return c - 'a' + 10
	case 'A' <= c && c <= 'F':
		return c - 'A' + 10
	}
	return 0
}

Break

Go的switch语句虽然是隐式中断,但break仍然在函数中会有用:

command := ReadCommand()
argv := strings.Fields(command)
switch argv[0] {
case "echo":
	fmt.Print(argv[1:]...)
case "cat":
	if len(argv) <= 1 {
		fmt.Println("Usage: cat <filename>")
		break
	}
	PrintFile(argv[1])
default:
	fmt.Println("Unknown command; try 'echo' or 'cat'")
}

Fall through

当满足switch的条件后想要进入后续的模块,请使用fallthrough关键字:

v := 42
switch v {
case 100:
	fmt.Println(100)
	fallthrough
case 42:
	fmt.Println(42)
	fallthrough
case 1:
	fmt.Println(1)
	fallthrough
default:
	fmt.Println("default")
}
// Output:
// 42
// 1
// default

其他例子:

// Unpack 4 bytes into uint32 to repack into base 85 5-byte.
var v uint32
switch len(src) {
default:
	v |= uint32(src[3])
	fallthrough
case 3:
	v |= uint32(src[2]) << 8
	fallthrough
case 2:
	v |= uint32(src[1]) << 16
	fallthrough
case 1:
	v |= uint32(src[0]) << 24
}

fallthrough 一定在代码的最后;你不能写这样的代码:

switch {
case f():
	if g() {
		fallthrough // Does not work!
	}
	h()
default:
	error()
}

然而,你可以通过使用 labeled 来解决这个问题:

switch {
case f():
	if g() {
		goto nextCase // Works now!
	}
	h()
    break
nextCase:
    fallthrough
default:
	error()
}

注意 fallthrough 在switch不生效的场景。

Multiple cases

如果想在同一情况下使用多个值,请使用逗号分隔的列表:

func letterOp(code int) bool {
	switch chars[code].category {
	case "Lu", "Ll", "Lt", "Lm", "Lo":
		return true
	}
	return false
}

Type switch

通过switch 可以进行类型的判断,获取 interface{} 的类型

func typeName(v interface{}) string {
	switch v.(type) {
	case int:
		return "int"
	case string:
		return "string"
	default:
		return "unknown"
	}
}

你可以声明一个函数,它将具有处理每种类型传值的类型:

func do(v interface{}) string {
	switch u := v.(type) {
	case int:
		return strconv.Itoa(u*2) // u has type int
	case string:
		mid := len(u) / 2 // split - u has type string
		return u[mid:] + u[:mid] // join
	}
	return "unknown"
}

do(21) == "42"
do("bitrab") == "rabbit"
do(3.142) == "unknown"

Noop case 没有操作

有时不需要采取行动的情况是有用的。这个得看具体的场景和应用需要做什么事情。

func pluralEnding(n int) string {
	ending := ""

	switch n {
	case 1:
	default:
		ending = "s"
	}

	return ending
}

fmt.Sprintf("foo%s\n", pluralEnding(1))  == "foo" //false
fmt.Sprintf("bar%s\n", pluralEnding(2))  == "bars" //false
fmt.Sprintf("foo%s", pluralEnding(1))  == "foo" //true
fmt.Sprintf("bar%s", pluralEnding(2))  == "bars" //true
//上述的\n导致字符串不一致

总结

上述介绍了switch的使用,有时候场景都是在断言的情况,判断这个值是什么类型。
以及某些数据链路上简化了if else 的使用。避免if else 过多的问题。