流控制
golang精简了控制语句,但足够我们使用。
if...else 语句需要注意一点的是对初始化语句的支持。
if x := xtest(); x == 0 { // 先执行xtest函数,再对x==0条件表示式判断布尔值
fmt.Println(x)
}
switch...case语句同样对初始化语句支持,此外不能出现重复的cacs值,单个case支持多条件匹配。
package main
import "fmt"
func xtest(x int) {
switch y := x + 1; y {
case 1, 2, 3: // 当x满足其中一项时即匹配
fmt.Println("1|2|3")
case 4:
fmt.Println("4")
case 5: // 该语句等同于case5 : break
default:
fmt.Println("Unkown")
}
}
func main() {
xtest(2)
xtest(3)
xtest(4)
}
switch可以省略条件表达式,默认为true。
package main
import "fmt"
func xtest(x int) {
switch { // 等同于 switch true
case x > 0:
fmt.Println("Positive", x)
case x < 0:
fmt.Println("Nagetive", x)
default:
fmt.Println("Zero", x)
}
}
func main() {
xtest(0)
xtest(1)
xtest(-1)
}
需要注意的是switch的条件表达式如果未false时,case匹配规则刚好相反,为不满足case的条件表达式时匹配。
package main
import "fmt"
func xtest(x int) {
switch false {
case x >= 0:
fmt.Println("Positive", x)
case x <= 0:
fmt.Println("Nagetive", x)
default:
fmt.Println("Zero", x)
}
}
func main() {
xtest(0)
xtest(1)
xtest(-1)
}
switch..case语句无需显示执行break语句,case执行完毕后自动跳出,如果需要继续执行下一个的case,可使用fallthrough,但不再匹配后续case条件表达式。fallthrough必须放在case块结尾.。
package main
import "fmt"
func xtest(x int) {
switch {
case x > 0:
fmt.Println("Positive", x)
fallthrough
case x < 0:
fmt.Println("Nagetive", x)
fallthrough
default:
fmt.Println("Zero", x)
}
}
func main() {
xtest(3)
}
golang中循环语句只有for一种,但是for的条件表达式有多种形式。
package main
import "fmt"
func main() {
for i := 0; i < 2; i++ { // 常用方式
fmt.Println("i=", i)
}
j := 0
for j < 2 { // 相当于 for _; j< 2; _
fmt.Println("j=", j)
j++
}
for { // 相当于for true
break
}
i := []string{"hello", "world"}
for k, s := range i { // 遍历s切片,k可以替换成_
fmt.Println(k, s)
}
}
函数
golang函数使用func定义函数,需要注意几点特性
1)函数无需前置声明
2)函数不支持嵌套定义
3)函数不支持重载
4)函数支持不定参数
5)函数支持多返回值
6)函数支持命名返回值
7)函数支持匿名函数和闭包
函数定义包括函数名、参数列表、返回值列表(可省略)和函数体。
func name(parameter list)(rusult list){
body
}
函数在golang中作为第一对象,可以作为参数、返回值、变量。相同返回值列表和参数列表的函数被认作一种数据类型。
package main
import "fmt"
type priInt func(int) int
func a(x int) int {
fmt.Println("Func a", x)
x++
return x
}
func b(x int) int {
fmt.Println("Func b", x)
return x
}
func test(x priInt) priInt {
x(1)
return x
}
func main() {
var funtest priInt
funtest = test(a)
funtest(2)
funtest = test(b)
funtest(2)
}
golang函数的参数列表支持相邻同类型合并,golang函数参数列表支持不定长参数,本质上不定长参数是切片。切片必须放在参数列表尾部。
package main
import "fmt"
func test(x, y int, a ...string) {
fmt.Println(x, y, a)
}
func main() {
test(1, 2, "hello", "abc")
}
golang函数支持多返回值,并且函数支持命名返回值,即返回值变量作为局部变量使用方式和参数一致。
package main
import "fmt"
func test1() (int, int, int) { // 多返回值函
return 1, 2, 3
}
func test2() (x int, y string) {
x = 1
y = "hello"
return // 隐式转化 相当于 return x, y
}
func main() {
a, b, _ := test1() // 多余不需要的返回值可使用_替换
fmt.Println(a, b)
c, d := test2()
fmt.Println(c, d)
}
golang函数支持匿名函数,与正常函数相比,减去了函数名称。匿名函数常用在函数内部嵌套上,匿名函数可以赋值给变量,或者作为参数、返回值。
package main
import "fmt"
func test(a func(int)) func(string) { // 匿名函数作为参数和返回值
a(1)
return func(str string) {
fmt.Println(str)
}
}
func main() {
func() {
fmt.Println("hello")
}() //声明匿名函数并直接调用
a := func() {
fmt.Println("world")
} //声明匿名函数并赋值给变量
a()
b := test(func(i int) {
fmt.Println("abc")
})
b("123")
}
Golang函数支持闭包特性,闭包指的是函数在使用中引用了函数上下文的环境。闭包会使上下文环境声明周期变长,如果上下文中定义了局部变量,该变量将被分配到堆中。
package main
import "fmt"
func test() func() {
x := 1
fmt.Println(x, &x)
return func() {
fmt.Println(x, &x) // 匿名函数引用了上下文变量x
}
}
func main() {
a := test()
a()
}
golang函数支持延时调用,当函数运行流程结束后,开始执行延时调用函数。使用defer可以向当前函数注册演示调用函数,当函数注册了多个延时调用函数,其执行顺寻是后注册的先执行。
package main
import "fmt"
func test() int {
x := 1
defer func() {
x++
fmt.Println("defer", x)
}()
defer func() {
x++
fmt.Println("defer2", x) // 先执行
}()
return x // 执行完后开始执行延时调用
}
func main() {
fmt.Println(test())
}
golang函数使用painc和recover实现类似try...catch的结构化异常捕捉。painc会立即终止当前函数流程,并执行当前函数延迟调用函数。
在延时调用函数中使用recover捕捉painc提交的错误对象。需要注意的是golang程序异常时,使用painc代表着程序终止。
package main
import (
"fmt"
"log"
)
func main() {
defer func() {
if err := recover(); err != nil { // 捕捉异常
log.Fatalln(err)
}
}()
panic("This is painc") // 终止函数流程
fmt.Println("main") // 不会执行
}