四、流程控制

2018-03-12  本文已影响21人  UUID

在一个稍微复杂的程序中,会根据程序运行的一些条件进行相应的操作。比如,打开一个文件,如果失败,则退出程序,如果成功,则读取文件内容并打印。总的来说,Go 语言的流程控制主要有 if else、for、goto、switch case、defer、continue、break、return。不同于其他语言,Go 条件判断不需要用()括号包含。

格式为 if exp {...} else {}。exp 为一个结果为bool类型的表达式,可以包含简短的变量申明赋值,函数求值操作。如果条件为真,则运行if{}后面的语句,否则,运行else 后面的语句。
if:

var x = 10
if x>5 {
  fmt.Println("x > 5") // x > 5
}

if else:

var x = 2
if x>5 {
  fmt.Println("x > 5") 
} else {
  fmt.Println("x <=  5") // x <= 5
}

exp表达式还可以包含一个简短的语句(赋值,函数求值等),如:

if x:=2; x>5{
  fmt.Println("x > 5") 
} else {
  fmt.Println("x <=  5") // x <= 5
}

如果有多个条件:
下面是将百分制转化为评级的代码

var x = `成绩`
if x >= 90 {
   fmt.Println("A")
} else if x >= 80 {
   fmt.Println("B")
} else if x >= 70 {
   fmt.Println("C")
} else if x >= 60 {
   fmt.Println("D")
} else {
   fmt.Println("不及格")
}

如果条件很多的话,太多的 if else 语句既影响美观,也影响代码的可读性。那有什么办法可以避免呢?那就是 switch case,接着往下看

格式如下:

switch sExp {
  case exp1:
      1....
  case exp2:
    2....
  default:
    3....
}

如果sExp 为exp1则执行1中的语句,如果为exp2则执行2中的语句,如果都不满足,则执行3中的语句。需要注意两点:
1、sExp 和exp1、exp2的类型必须一致,如果是bool类型的话,则sExp可以省略
2、一个case 分支的语句执行完成之后,不会再执行switch中其他分支的语句,对比其他语言,相当于Go后面自动追加了break语句,当然,你也可以在case中使用break来终止switch case。

给定一个数值,如果为1则输出1,如果为2则输出2,其他值输出/:

var x int = 3
switch x {
  case 1:
    fmt.Println("1")
  case 2:
    fmt.Println("2")
  default:
    fmt.Println("/")
}

上个百分制转换的例子,可以用switch来写,表达式结果为bool 则sExp可以省略:

var x = `成绩`
switch {
  case x >= 90 :
     fmt.Println("A")
  case x >= 80 :
     fmt.Println("B")
  case x >= 70 :
     fmt.Println("C")
  case x >= 60 :
     fmt.Println("D")
  default:
     fmt.Println("不及格")
}

如果在一个分支执行完成之后,还要继续执行其他分支呢?那就使用fallthrough

var x = `成绩`
switch {
  case x >= 90 :
     fmt.Println("x >= 90")
     fallthrough
  case x >= 80 :
     fmt.Println("x >= 80")
     fallthrough
  case x >= 70 :
     fmt.Println("x >= 70")
     fallthrough
  case x >= 60 :
     fmt.Println("x >= 60")
  default:
     fmt.Println("不及格")
}
//x = 99 则输出
x >= 90
x >= 80
x >= 70
x >= 60

相同条件如果执行相同的语句,而且条件很多的话,使用 fallthrough可能会不太美观,毕竟编程是一种艺术,是吧?还有一种方式,相同条件可以用逗号(,)隔开,就像这样:

func shouldEscape(c byte) bool {
    switch c {
    case ' ', '?', '&', '=', '#', '+', '%':
        return true
    }
    return false
}

Go中的循环只有一个,那就是for,那就意味着for是很强大的。for的格式:

for exp1; exp2; exp3 {
  ...
}

exp1为初始化语句,在for循环开始之前执行,而且只执行一次;
exp2为判断语句,结果为bool类型,为真则执行一次循环;
exp3为迭代语句,在每轮循环之后,下轮循环之前执行。
exp1、exp2、exp3都不是必须的。

100以内整数求和:

result := 0
for i:=1; i < 100; i++ {
  result += i // result = result + i
}
fmt.Println(result)

省去初始化语句:

i, result := 1, 0
for ; i < 100; i++ {
  result += i // result = result + i
}
fmt.Println(result)

省去初始化语句和迭代语句:

i, result := 0, 0
for i < 100 {
  result += i // result = result + i
  i++
}
fmt.Println(result)

省去所有语句,相当于其他语言的while循环:

i, result := 1, 0
for {
  if i < 100 {
    result += i // result = result + i
    i++
  } else {
    break
  }
}
fmt.Println(result)

怎么样?写法很多吧,而且上面几种写法的运行结果都一样。
有人会很奇怪,为什么最后一个程序没有一直运行下去?因为当i = 100时,流程break了,就是循环中断了。那就看下break

for循环可以嵌套,即在循环里面还有循环。比如,我们可以打印一个九九乘法表

for i:=1; i<10; i++ {
  for j:=1; j<=i; j++ {
    fmt.Fprintf(os.Stdout,"%2d\t",i*j)
  }
  fmt.Println()
}

fmt.Fprintf 是格式化输出的,也许你已经发现了os.Stdout其实就是屏幕。

break 就是用来中断 for 循环的

i := 1
for{
  if i > 5{
    break
  }
  fmt.Println(i)
  i++
}
// 1 2 3 4 5

这样,就退出循环了。
break 还有一个作用,就是可以跳转到一个指定的lable。

for {
  ......
  LABLE:
  for ... {
    .....
      for {
          if ... {
            break LABLE
          }
      }
  }
}

LABLE只是一个标签的名字而已,后面跟: 推荐名称为大写。这样当第三层for 满足某种情况的时候,就会跳转到lable 处,继续执行。当然,这个只是个例子,实际情况中应该尽量避免循环嵌套的情况。

如果只是想跳过某些情况,但是并不想中断整个循环,那怎么办?不用担心,你想到的Go已经帮你实现了,那就是continue,接着往下看

接着上个例子,小于5的全部打印,,大于10则循环结束,其余的只打印偶数。

i := 1
for{
  if i > 10 {
    break
  } 
  if i > 5 && i%2 != 0 {//当然可以判断为偶数就打印,这里只是为了举个例子
    i++
    continue
  } 
  fmt.Println(i)
  i++
}

return 语句用于退出当前方法。可以不带返回值,也可以带一个或者多个,这需要根据函数定义决定。

....
return

break + lable 的方式让程序跳转到指定地方,goto语句也可以实现跳转,但是,Go不推荐使用,所以在程序中应该极力避免使用。
defer 将会在下一篇讲到。

上一篇 下一篇

猜你喜欢

热点阅读