go控制流和一些特殊语句

send和receive语句

send、receive操作是针对channel的
send : ch <- a
receive: a := <- ch

++--语句

在go中++--是一个赋值语句,而不是一个表达式因此不能像C/C++那样编写如下代码:
a = b++
同时在go中只有后置,没有前置写法。

a++
a--

if语句

ifif是编程语言中最简单的条件分支判断语句,几乎所有语言都有,所以就不介绍功能,主要介绍下写法
if语句中的条件表达式不需要加上括号

if a > 0 {
    fmt.Println("a > 0")
} else {
    fmt.Println("a <= 0")
}

if的语句中可以在判断语句中声明变量,这个变量只在if语句作用域内部有效

if a := calc(); a < 0 {
    fmt.Println("result:", a)
}

switch语句

switch语句中首先执行switch后面的表达式,然后执行case后面的表达式,并且是从上到下,从左到右执行,一旦有一个满足,则不再继续执行后面的操作。
switch后面不跟表达式则默认为true
case后面可以跟很多个表达式,其中一个满足则执行该case下的语句
默认情况下case下的语句执行之后会跳出switch,如果需要继续执行,使用fallthrough关键字,即使是default也可以fallthrough
if一样可以在switch表达式中声明变量
switch可以最多有一个default,当没有case条件满足的情况下执行default

switch tag {
    case 0, 1, 2, 3: s1()
    case 4, 5, 6, 7: s2()
}
switch {
    case x < y : s1()
    case x > y : s2()
    case x = y : s3()
}
switch x := f(); {  // default is true
    case x < 0: return -x
    default: return x
}

switch出了支持上述普通的表达式判断以外,还支持类型switch,这种情况下不能使用fallthrough
type有可能是nil(当变量是一个nil interface的时候)

switch i := x.(type) {
case nil:
    print("x is nil)
case int:
    print("x is int")
case bool, string:
    print("x is bool or string")
default:
    print("x is a don't know type")
}

for语句

for语句有三种形式:

  • 无限循环
for {
    dosomething()
}
  • 类似C/C++的while形式
for a < b {
    dosomething()
}
  • 标准的for形式
for i := 0; i < 10; i++ {
    dosomething()
}

对于数组、slice、string、map、channel可以是用for range的形式,具体情况如下:

  • slice、array,返回一个index和index对应的element。
for index, value := range a {
}
  • string,返回一个index和一个rune,index以byte计数,是rune在string的起始byte的index。一个rune占几个byte取决于该unicode的长度
b := "中文"
for index, unicode := range a {
    fmt.Println(index, string(unicode))
}
//输出
//0 中
//3 文
  • map,返回key和value
for key, value := range amap {
}
  • channel,一个双向或者是接收channel,当没有数据的时候会阻塞,知道收到数据为止,channel是nil会永久阻塞,当channel关闭,循环退出
for k := range ch {}

go语句

go语句创建一个goroutine并在该goroutine中执行函数,可以是一个匿名函数

go log(i)
go func(i int) {
    log(i)
}(1)

select语句

select语句主要用于对channel的选择,可以是接收或者发送,当操作成功的时候的时候选择对应的case,如果有多个case成功,随机选择其中一个执行。

var a []int
var c, c1, c2, c3, c4 chan int
var i1, i2 int
select {
case i1 = <-c1:
    print("received ", i1, " from c1\n")
case c2 <- i2:
    print("sent ", i2, " to c2\n")
case i3, ok := (<-c3):  // same as: i3, ok := <-c3
    if ok {
        print("received ", i3, " from c3\n")
    } else {
        print("c3 is closed\n")
    }
case a[f()] = <-c4:
    // same as:
    // case t := <-c4
    //  a[f()] = t
default:
    print("no communication\n")
}

for {  // send random sequence of bits to c
    select {
    case c <- 0:  // note: no statement, no fallthrough, no folding of cases
    case c <- 1:
    }
}
select {}  // block forever

return语句

return结束一个函数,并且可以返回一个或者多个返回值

func noResult() {
    return
}
func twoResult() (int, bool) {
    return 1, true
}
func towResultWithVariabl() (a int, b bool) {
    a = 1
    b = true
    return   //same as return a, b
}

break

break用于跳出最内层的for switch select语句,也可以通过使用label来跳出指定的label标记的for switch select

OUTER_LOOP:
for i := 0; i < 10; i++ {
    for j := 0; j < 10; j++ {
        switch a[i][j] {
            case nil : break   //跳出本次switch,same as no break.
            case item: break OUTER_LOOP   //直接跳出最外层循环
        }
    }
}

continue

continue用于直接开始最内层循环的下一个迭代,也可以通过label来继续label标记的for loop。

RowLoop:
    for y, row := range rows {
        for x, data := range row {
            if data == endOfRow {
                continue RowLoop
            }
            row[x] = data + bias(x, y)
        }
    }

goto

和C/C++中的goto一样,跳转到指定的label处,goto不能跳过作用域中的变量声明,也不能跳转到不同的作用域中去

goto L
v := 3
L:
 dosomething() //错误,跳过了v的声明

if n%2 == 1 {
    goto L1
}
for n > 0 {
    fn()
    n--
L1 
    fn()
    n--
}
//错误,从一个作用域跳转到另外一个作用域

defer

defer是一个函数的执行推迟到其调用defer的函数的return之前执行。
多个defer的执行顺序是和编写顺序逆序执行的

func dosomething() int {
}
func do() int {
    lock(l)
    defer unlock(l) //unlock will execute after dosomething
    ...
    return dosomething()
}

for i := 0; i < 10; i++ {
    defer fmt.Println(i)
}
这样将输出9到0

recover and panic

panic将直接从调用panic的当前函数中返回,并且如果panic没有被recover,那么程序将直接crash。
可以通过defer和recover来从panic错误中恢复。

func protect(g func()) {
    defer func() {
        log.Println("done")  // Println executes normally even if there is a panic
        //catch panic 并且从panic中恢复,以保证程序不会crash,而是可以继续执行。
        if x := recover(); x != nil {
            log.Printf("run time panic: %v", x)
        }
    }()
    log.Println("start")
    g()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值