6.1 if语句

go语言的常用控制流程有if和for,没有while, 而switch和goto是为了简化代码,降低重复代码,属于扩展的流程控制。

if语句的结构:

  1. if 布尔表达式 {
  2. /* 在布尔表达式为 true 时执行 */
  3. }
  4. if 布尔表达式 {
  5. /* 在布尔表达式为 true 时执行 */
  6. } else {
  7. /* 在布尔表达式为 false 时执行 */
  8. }
  9. if 布尔表达式1 {
  10. /* 在布尔表达式1为 true 时执行 */
  11. } else if 布尔表达式2{
  12. /* 在布尔表达式1为 false ,布尔表达式2为true时执行 */
  13. } else{
  14. /* 在上面两个布尔表达式都为false时,执行*/
  15. }
package main

import "fmt"

func main() {
   /* 定义局部变量 */
   var a int = 10

   /* 使用 if 语句判断布尔表达式 */
   if a < 20 {
       /* 如果条件为 true 则执行以下语句 */
       fmt.Printf("a 小于 20\n" )
   }
   fmt.Printf("a 的值为 : %d\n", a)
}

if还有一个变体也很常用

package main

import (  
    "fmt"
)

func main() {  
    if num := 10; num % 2 == 0 { //checks if number is even
        fmt.Println(num,"is even") 
    }  else {
        fmt.Println(num,"is odd")
    }
}
if err := Connect(); err != nil {

}

这种写法可 以将返回值与判断放在一行进行处理,而且返回值的作用范围被限制在if、 else 语句组合中。
提示:
在编程中,变量在其实现了变量的功能后 ,作用范围越小 ,所造成的问题可能性越小,每一个变量代表一个状态,有状态的地方,状态就会被修改,函数的局部变量只会影响一个函数的执行, 但全局 变量可能会影响所有代码的执行状态,因此限制变量的作用范围对代码的稳定性有很大的帮助 。

package main

import (
    "errors"
    "fmt"
)

func test() error {
    return errors.New("error")
}

func main() {
    if err := test(); err != nil {
        fmt.Println("error happen")
    }
    fmt.Println(err) //此处会报错
}

6.2 for循环

  1. Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。
    //和 C 语言的 for 一样:
    for init; condition; post { }
    //和 C 的 while 一样:
    for condition { }
    //和 C 的 for(;;) 一样:
    for { }
    
  • init: 一般为赋值表达式,给控制变量赋初值;
  • condition: 关系表达式或逻辑表达式,循环控制条件;
  • post: 一般为赋值表达式,给控制变量增量或减量。

for语句执行过程如下:

  • 1、先对表达式 1 赋初值;
  • 2、判别赋值表达式 init 是否满足给定条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。

6. 条件/循环语句 - 图1

  1. for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
    for key, value := range oldMap {
     newMap[key] = value
    }
    
    ```go package main import “fmt”

func main() { strings := []string{“bobby”, “imooc”} for i, s := range strings { fmt.Println(i, s) }

    numbers := [6]int{1, 2, 3, 5}
    for i,x:= range numbers {
            fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
    }  

}

<a name="AHxEm"></a>
# 6.3 goto语句
Go语言的goto语句可以无条件转移到过程中指定的行。<br />goto语句通常与条件语句配合使用,可用来实现条件转移,构成循环,跳出循环体等功能。<br />但是,在结构化程序设计中一般不主张使用goto语句,以免造成程序流程的混乱,使理解和调试程序都产生困难。<br />goto语法格式如下:
```powershell
goto label;
...
label:statement;

6. 条件/循环语句 - 图2

package main

import "fmt"

func main() {
    /* 定义局部遍历 */
    var a int = 10

    /* 循环 */
LOOP:
    for a < 20 {
        if a == 15 {
            /* 跳过迭代 */
            a = a + 1
            goto LOOP
        }
        fmt.Printf("a的值为:%d\n", a)
        a++
    }
}

应用场景

使用goto退出多层循环

package main

import "fmt"

func main() {
    var breakAgain bool
    //外循环
    for x := 0; x < 10; x++ {
        //内循环
        for y := 0; y < 10; y++ {
            //满足某个条件时 退出循环
            if y == 2 {
                //设置退出标记
                breakAgain = true
                //退出本次循环
                break
            }
        }
        // 根据标记 还需要退出一次循环
        if breakAgain {
            break
        }
    }
    fmt.Println("done")
}
//优化后
package main

import "fmt"

func main() {
    for x := 0; x < 10; x++ {
        for y := 0; y < 10; y++ {
            if y == 2 {
                //跳转到标签
                goto breakHere
            }
        }
    }
    //手动返回, 避免执行进入标签
    return
    //标签
breakHere:
    fmt.Println("done")
}

使用goto集中处理错误

多处错误处理存在代码重复时是非常棘手的,例如:

    err := firstCheckError()
    if err != nil {
        fmt.Println(err)
        exitProcess()
        return
    }
    err = secondCheckError()
    if err != nil {
        fmt.Println(err)
        exitProcess()
        return
    }
    fmt.Println("done")

上述代码修改一下

    err := firstCheckError()
    if err != nil {
        goto onExit
    }
    err = secondCheckError()
    if err != nil {
        goto onExit
    }
    fmt.Println("done")
    return
onExit:
    fmt.Println(err)
    exitProcess()

6.4 switch语句

  1. switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
    switch var1 {
     case val1:
         ...
     case val2:
         ...
     default:
         ...
    
    ```go package main

import “fmt”

func main() { / 定义局部变量 / var grade string = “B” var marks int = 90

switch marks { case 90: grade = “A” case 80: grade = “B” case 50,60,70 : grade = “C” default: grade = “D”
}

switch { case grade == “A” : fmt.Printf(“优秀!\n” )
case grade == “B”, grade == “C” : fmt.Printf(“良好\n” )
case grade == “D” : fmt.Printf(“及格\n” )
case grade == “F”: fmt.Printf(“不及格\n” ) default: fmt.Printf(“差\n” ); } fmt.Printf(“你的等级是 %s\n”, grade );
}

<a name="de7sV"></a>
## Type Switch
switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。<br />Type Switch 语法格式如下:
```go
switch x.(type){
    case type:
       statement(s);      
    case type:
       statement(s); 
    /* 你可以定义任意个数的case */
    default: /* 可选 */
       statement(s);
}
package main

import "fmt"

func main() {
   var x interface{}

   switch i := x.(type) {
      case nil:  
         fmt.Printf(" x 的类型 :%T",i)                
      case int:  
         fmt.Printf("x 是 int 型")                      
      case float64:
         fmt.Printf("x 是 float64 型")          
      case func(int) float64:
         fmt.Printf("x 是 func(int) 型")                      
      case bool, string:
         fmt.Printf("x 是 bool 或 string 型" )      
      default:
         fmt.Printf("未知型")    
   }  
}

一分支多值

不同的 case 表达式使用逗号分隔。

var a = "mum"
switch a {
    case "mum", "daddy":
    fmt.Println("family")
}

分支表达式

var r int = 11
switch {
    case r > 10 && r < 20:
    fmt.Println(r)
}

6.5 python中为什么没有switch

查看Python官方:PEP 3103-A Switch/Case Statement

发现其实实现Switch Case需要被判断的变量是可哈希的和可比较的,这与Python倡导的灵活性有冲突。在实现上,优化不好做,可能到最后最差的情况汇编出来跟If Else组是一样的。所以Python没有支持。

https://www.python.org/dev/peps/pep-3103/

score = 90
switch = {
    90: lambda : print("A"),
    80: lambda : print("B"),
    70: lambda : print("C"),
}

switch[score]()
class switch(object):
    def __init__(self, value):
        self.value = value
        self.fall = False

    def __iter__(self):
        """Return the match method once, then stop"""
        yield self.match
        raise StopIteration

    def match(self, *args):
        """Indicate whether or not to enter a case suite"""
        if self.fall or not args:
            return True
        elif self.value in args: # changed for v1.5, see below
            self.fall = True
            return True
        else:
            return False

# The following example is pretty much the exact use-case of a dictionary,
# but is included for its simplicity. Note that you can include statements
# in each suite.
v = 'ten'
for case in switch(v):
    if case('one'):
        print 1
        break
    if case('two'):
        print 2
        break
    if case('ten'):
        print 10
        break
    if case('eleven'):
        print 11
        break
    if case(): # default, could also just omit condition or 'if True'
        print "something else!"
        # No need to break here, it'll stop anyway

# break is used here to look as much like the real thing as possible, but
# elif is generally just as good and more concise.

# Empty suites are considered syntax errors, so intentional fall-throughs
# should contain 'pass'
c = 'z'
for case in switch(c):
    if case('a'): pass # only necessary if the rest of the suite is empty
    if case('b'): pass
    # ...
    if case('y'): pass
    if case('z'):
        print "c is lowercase!"
        break
    if case('A'): pass
    # ...
    if case('Z'):
        print "c is uppercase!"
        break
    if case(): # default
        print "I dunno what c was!"

# As suggested by Pierre Quentel, you can even expand upon the
# functionality of the classic 'case' statement by matching multiple
# cases in a single shot. This greatly benefits operations such as the
# uppercase/lowercase example above:
import string
c = 'A'
for case in switch(c):
    if case(*string.lowercase): # note the * for unpacking as arguments
        print "c is lowercase!"
        break
    if case(*string.uppercase):
        print "c is uppercase!"
        break
    if case('!', '?', '.'): # normal argument passing style also applies
        print "c is a sentence terminator!"
        break
    if case(): # default
        print "I dunno what c was!"

# Since Pierre's suggestion is backward-compatible with the original recipe,
# I have made the necessary modification to allow for the above usage.