ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 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) } ```