条件选择

条件选择

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 类型
}
下一页