5.6. 控制流
Go语言的控制结构与C的基本相同但是有些地方还是不同。Go中没有do, while这样的循环,for与switch 也非常的灵活。if和switch可以有一个初始化语句 就像for一样。还增加了一个type switch(类型选择)和多通道复用(multiway communications multiplexer)的select. 语法有一点点区别,圆括号大部分是 不需要的但是大括号必须始终括号分隔.
5.6.1. If
Go中简单的if实例:
if x > 0 {
return y
}
建议在写if语句的时候采用多行。这是一种非常好的编程风格, 特别是在控制结构体里面有return或break的时候.
if和switch允许初始化声明,就可以使用本地变量(local variable).
if err := file.Chmod(0664); err != nil {
log.Stderr(err)
return err
}
在Go的库文件中,你可能经常看到if语句不进入下一条语句是因为函数在 break,continue,goto或reurn结束, else可以省略。
f, err := os.Open(name, os.O_RDONLY, 0)
if err != nil {
return err
}
codeUsing(f)
一般的代码都会考虑错误的处理,如果没有出错的情况就继续运行但是在出错的时候 函数就会返回,所以在这里不需要else语句。
f, err := os.Open(name, os.O_RDONLY, 0)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
return err
}
codeUsing(f, d)
5.6.2. For
Go中的for循环与C相似,但是也有不同的地方。Go只有for和 while, 没有do-while语句。这里有三种方式,只有一种方式 使用了分号。
// Like a C for
for init; condition; post { }
// Like a C while
for condition { }
// Like a C for(;;)
for { }
短声明使得在循环里声明下标变量很容易。
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
如果你要遍历一个array, slice, string or map or 从通道(channel)读数 range将是你最好的选择。
var m map[string]int
sum := 0
for _, value := range m { // key is unused
sum += value
}
对于字符串,range能为你更好的工作,比如解析UTF-8并单独输出Unicode字符.
for pos, char := range "日本語" {
fmt.Printf("character %c starts at byte position %d\n", char, pos)
}
打印出:
character 日 starts at byte position 0
character 本 starts at byte position 3
character 語 starts at byte position 6
最后,Go中没有逗号运算符(comma operator)和++与--运算, 如果你想执行多个变量在for语句中,你可以使用并行参数(parallel assignment).
// Reverse a
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
5.6.3. Switch
Go中的switch要比C更全面,C的表达式仅仅只有常数或整数。 每个分支(cases)从上到下进行匹配取值, 如果switch没有表达式 那么switches是真。所有才有可能使用switch替换
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
}
没有自动掉到下一分支,但分支可以是逗号分隔的列表:
func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return false
}
这个操作数组的程序和上面的相似是通过两个switch语句。
// Compare returns an integer comparing the two byte arrays
// lexicographically.
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b
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就是 用关键字type插入到接口类型后面的括号来判断类型, 如果switch 在表达式中声明了一个变量,在分支上就有相应的类型。
switch t := interfaceValue.(type) {
default:
fmt.Printf("unexpected type %T", t) // %T prints type
case bool:
fmt.Printf("boolean %t\n", t)
case int:
fmt.Printf("integer %d\n", t)
case *bool:
fmt.Printf("pointer to boolean %t\n", *t)
case *int:
fmt.Printf("pointer to integer %d\n", *t)
}