zoukankan      html  css  js  c++  java
  • go——流程控制

    Go在流程控制方面的特点如下:
      没有do和while循环,只有一个更广义的for语句。
      switch语句灵活多变,还可以用于类型判断。
      if语句和switch语句都可以包含一条初始化子语句。
      break语句和continue语句可以后跟一条标签(label)语句,以标识需要终止或继承的代码块。
      defer语句可以使我们更加方便地执行异常捕获和资源回收任务。
      select语句也用于多分支选择,但只与通道配合使用。
      go语句用于异步启动goroutine并执行指定函数。

    1.代码块和作用域

    代码块就是一个由花括号包裹地表达式和语句的序列。当然,代码块中也可以不包含任何内容,即:空代码块。
    除了显式地代码块之外,还有一些隐式地代码块,说明如下:

       所有Go代码形成了一个最大地代码块,即:全域代码块
      每一个代码包中的代码共同组成了一个代码块,即:代码包代码块
      每一个源码文件都是一个代码块,即:源码文件代码块
      每一个if、for、switch和select语句都是一个代码块;
      每一个在switch或select语句中的case分支都是一个代码块。

    在Go中,使用代码块表示词法上的作用域范围,具体规则如下:
      一个预定义标识符的作用域是全域代码块
      表示一个常量、变量、类型或函数(不包括方法),且声明在函数之外的标识符的作用域是当前的代码包代码块;
      被导入的代码包的名称的作用域是当前的源码文件代码块;
      表示方法接收者、方法参数、类型或函数的标识符,如果被声明在函数内部,那么作用域就是包含其声明的那个最内层的代码块。

    此外,我们还可以重新声明已经在外层代码块中声明过的标识符。
    当在内层代码块中使用这个标识符时,它表示的总是那个在该代码块中与它绑定在一起的那个程序实体。
    可以说,此时在外层代码块中声明的那个同名标识符并屏蔽了。例如

    package main
    import (
    	"fmt"
    )
    var v = "1,2,3"  //最外层标识符
    func main() {
    	v := []int{1, 2, 3}  //第二次赋值
    	if v != nil {
    		var v = 123  //第三次赋值
    		fmt.Printf("%v
    ", v)  
    	}
    }
    //结果:123
    

    其中,变量v被声明3次。当判断v是否非nil时,v代表的时那个切片。
    而当v被打印时,它代表的确实那个整数。

    2.if语句

    if语句会根据条件表达式来执行两个分支中的一个。
    如果那个表达式的结果是true,那么if分支会被执行,否则else分支会被执行。

    例如:

    var number int
    //省略
    if 100 < number {
    	number++
    }
    

    又如:

    if 100 < number {
    	number++
    }else {
    	number--
    }
    

    if语句还可以包含一条初始化的子语句,用于初始化局部变量:

    if diff := 100 - number;100 < diff {
    	number++
    }else {
    	number--
    }
    

    此外,它还支持串联:

    if diff := 100 - number;100 < diff {  //先进行赋值操作,在逻辑判断
    	number++
    }else if 200 < diff {
    	number--
    }else {
    	number -= 2
    }
    

    其中条件表达式的求值顺序是自上而下的。只有第一个结果为true的表达式对应的分支会被选中并执行。
    并且,只要上面的表达式的结果为true,其后的表达式就不会被求值。

    3.switch语句

    switch语句也提供了一种多行分支执行的方法。
    它会用一个表达式或类型说明符与每一个case进行比较,并决定执行哪一个分支。

    (1)表达式switch语句

    在表达式switch语句中,switch表达式和所有case携带的表达式(也称为case表达式)都会被求值,并且执行顺序是自左向右、自下而上。
    只有第一个与switch表达式的求值结果相等case表达式分支会被执行。
    如果没有找到匹配的case表达式并且存在default case,那么default case的分支会执行。
    注意,default case最多只有一个。
    另外,switch表达式可以省略,这时true会作为switch表达式的结果。
    示例:

    package main
    import (
    	"fmt"
    )
    var content string
    //省略
    switch content {
    	default:
    		fmt.Println("不知道什么语言")
    	case "python":
    		fmt.Fprintln("一门解释型语言")
    	case "go":
    		fmt.Println("一门编译型语言")
    

    switch语句也可以包含一条子语句来初始化局部变量:

    switch lang := strings.TrimSpace(content); lang {
    	default:
    		fmt.Println("不知道什么语言")
    	case "python":
    		fmt.Fprintln("一门解释型语言")
    	case "go":
    		fmt.Println("一门编译型语言")
    }
    

    可以在switch语句中使用fallthrough,来向下一个case语句转移流程控制权。

    switch lang := strings.TrimSpace(content); lang {
    	case "Ruby":
    		fallthrough
    	case "Python":
    		fmt.Println("一门解释型语言")
    	case "C","Java","Go":
    		fmt.Println("一门编译型语言")
    	default:
    		fmt.Println("什么都不是")
    }

    只要lang的值等于Ruby或python,第2个case语句就会执行。其实可以放在一个case中。
    每个case语句中的case表达式还可以有多个。
    另外,break语句可以用来退出当前的switch语句。它由一个break关键字和一个可选的标签组成。

    (2)类型switch语句

    类型switch语句将对类型进行判定,而不是值。

    var v interface{}
    //省略
    switch v.(type) {
    	case string:
    		fmt.Printf("The string '%s'.
    ",v.(string))
    	case int,uint,int8,uint8:
    		fmt.Printf("The integer is %d.
    ",v)
    	default:
    		fmt.Printf("Unsupported value.(type%T)
    ",v)
    }
    

    类型switch语句的switch表达式会包含一个特殊的类型断言,例如v.(type)。
    它虽然特殊,但是也要遵循类型断言的规则。其次,每个case表达式中包含的都是类型字面量而不是表达式。
    最后fallthrough语句不允许出现在类型switch语句中。

    类型断言switch语句的switch表达式还有一种变形写法。

    switch i := v.(type) {
    	case string:
    		fmt.Printf("The string '%s'.
    ",i)
    	case int,uint,int8,uint8:
    		fmt.Printf("The integer is %d.
    ",i)
    	default:
    		fmt.Printf("Unsupported value.(type%T)
    ",i)
    }
    

    这里的i := v.(type)使经类型转换后的值得以保存。i的类型一定会是v的值的实际类型。

    4.for语句

    for语句用于根据给定的条件重复执行一个代码块。这个条件或由for子句直接给出,或从range子句中获得。
    (1)for子句

    一条for语句中可以携带一条for子句。for子句可以包含初始化子句、条件子句和后置子句。

    var number int
    for i := 0; i < 100; i++ {  //i := 0初始化语句  i++后置语句
    	number++
    }
    
    var j uint = 1
    for;j%5 != 0; j *= 3 {  //省略初始化子句
    	number++
    }
    
    for k := 1; k%5 != 0; {  //省略后置子句
    	k *= 3
    	number++
    }
    

    在for子句的初始化子句和后置子句同时被省略,或者其中的所有部分都省略的情况下,分隔符":"可以省略。

    var m = 1
    for m < 50 {
    	m *= 3
    }
    

    (2)range子句

    一条for语句可以携带一条range语句,这样就可以迭代出一个数组或者切片值中的每个元素、
    一个字符串中的每个字符、或者一个字典值中的每个键-元素对,以及持续地接收一个通道类型值中的元素。
    随着迭代的进行,每一次获取的迭代值(索引、元素、字符或键-元素对)都会赋给相应的迭代变量。

    ints := []int{1, 2, 3, 4, 5}
    for i, d := range ints {
    	fmt.Printf("Index:%d,value:%d
    ", i, d)
    }
    

    在range关键字右边的是range表达式。range表达式一般只会在迭代开始前被求值一次.
    针对range表达式的不同结果,range子句的行为也会不同。

    使用range子句,有3点需要注意:
      a.若对数组、切片或字符串值进行迭代,且:=左边只有一个迭代变量时,一定要小心。
       这时只会得到其中元素的索引,而不是元素本身。
      b.迭代没有任何元素的数组值、为nil的切片值、为nil的字典值或为""的字符串值,
        并不会执行for语句中的代码。for语句在一开始就会直接结束执行,因为这些值的长度都为0.
      c.迭代为nil的通道值会让当前流程永远阻塞在for语句上。

  • 相关阅读:
    oracle 数据库服务名怎么查
    vmware vsphere 6.5
    vSphere虚拟化之ESXi的安装及部署
    ArcMap中无法添加ArcGIS Online底图的诊断方法
    ArcGIS中字段计算器(高级计算VBScript、Python)
    Bad habits : Putting NOLOCK everywhere
    Understanding the Impact of NOLOCK and WITH NOLOCK Table Hints in SQL Server
    with(nolock) or (nolock)
    What is “with (nolock)” in SQL Server?
    Changing SQL Server Collation After Installation
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/10089895.html
Copyright © 2011-2022 走看看