条件选择
条件选择
if
Go 中,一个简单 if 语句看起来是这样的:
if x > 0 {
return y
}
编写代码时,应尽量减少条件的嵌套深度。如方法返回错误时,应尽量提前结束。应当尽可能减少正常逻辑代码的嵌套深度,这有利于提高代码的可读性,便于快速分辨出哪些还是正常逻辑代码,例如: 这是一个不好的代码风格,正常逻辑代码被缩进在 else 分支里面:
if err != nil {
// error handling
} else {
// normal code
}
更好的写法:
if err != nil {
// error handling
return // or continue, etc.
}
// normal code
如果 if 语句带有初始化语句,例如:
if x, err := f(); err != nil {
// error handling
return
} else {
// use x
}
那么将初始化的短声明赋值语句单独写成一行:
x, err := f()
if err != nil {
// error handling
return
}
// use x
Switch
Go 的 switch 比 C 的更通用。其表达式无需为常量或整数,case 语句会自上而下逐一进行求值直到匹配为止。若 switch 后面没有表达式,它将匹配 true,因此,我们可以将 if-else-if-else 链写成一个 switch,这也更符合 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
}
switch 并不会自动下溯,但 case 可通过逗号分隔或者 fallthrough 来列举相同的处理条件。
func shouldEscape(c byte) (b bool) {
switch c {
case ' ', '?', '&', '=', '#', '+':
fallthrough
case '%':
b = true
default:
b = false
}
return
}
尽管它们在 Go 中的用法和其它类 C 语言差不多,但 break 语句可以使 switch 提前终止。不仅是 switch,有时候也必须打破层层的循环。在 Go 中,我们只需将标签放置到循环外,然后 “蹦”到那里即可。下面的例子展示了二者的用法。
Loop:
for n := 0; n < len(src); n += size {
switch {
case src[n] < sizeOne:
if validateOnly {
break
}
size = 1
update(src[n])
case src[n] < sizeTwo:
if n+1 >= len(src) {
err = errShortInput
break Loop
}
if validateOnly {
break
}
size = 2
update(src[n] + src[n+1]<<shift)
}
}
当然,continue 语句也能接受一个可选的标签,不过它只能在循环中使用。作为这一节的结束,此程序通过使用两个 switch 语句对字节数组进行比较:
// Compare 按字典顺序比较两个字节切片并返回一个整数。
// 若 a == b,则结果为零;若 a < b;则结果为 -1;若 a > b,则结果为 +1。
func Compare(a, b []byte) int {
for i := 0; i < len(a) && i < len(b); i++ {
switch {
case a[i] > b[i]:
return 1
case a[i] < b[i]:
return -1
}
}
switch {
case len(a) > len(b):
return 1
case len(a) < len(b):
return -1
}
return 0
}
类型选择
switch 也可用于判断接口变量的动态类型。如 类型选择 通过圆括号中的关键字 type 使用类型断言语法。若 switch 在表达式中声明了一个变量,那么该变量的每个子句中都将有该变量对应的类型。
var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
fmt.Printf("unexpected type %T", t) // %T 输出 t 是什么类型
case bool:
fmt.Printf("boolean %t\n", t) // t 是 bool 类型
case int:
fmt.Printf("integer %d\n", t) // t 是 int 类型
case *bool:
fmt.Printf("pointer to boolean %t\n", *t) // t 是 *bool 类型
case *int:
fmt.Printf("pointer to integer %d\n", *t) // t 是 *int 类型
}