go语言 条件语句和循环语句

247 阅读2分钟

2.6 条件语句和循环语句

2.6.1 if语句

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

if语句的结构:

if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
}

if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
} else {
  /* 在布尔表达式为 false 时执行 */
}

if 布尔表达式1 {
   /* 在布尔表达式1为 true 时执行 */
} else if 布尔表达式2{
   /* 在布尔表达式1为 false ,布尔表达式2为true时执行 */
} else{
   /* 在上面两个布尔表达式都为false时,执行*/
}
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) //此处会报错
}

2.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循环,执行循环体外语句。
  1. for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap {
    newMap[key] = value
}
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)
        }  
}

2.6.3 goto语句

Go 语言的 goto 语句可以无条件地转移到过程中指定的行。

goto 语句通常与条件语句配合使用。可用来实现条件转移, 构成循环,跳出循环体等功能。

但是,在结构化程序设计中一般不主张使用 goto 语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难。

goto 语法格式如下:

goto label;

..

.

label: statement;

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()

2.6.4 switch语句

  1. switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}
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 );      
}

Type Switch

switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。

Type Switch 语法格式如下:

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)
}

2.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.

2.7 最常用的复杂数据类型 - map、数组、 列表和切片

Xnip2021-03-31_10-37-20.png