14-流程控制语句

带range子句的for语句

numbers1 := []int{1, 2, 3, 4, 5, 6}     // 声明并初始化int类型的切片
for i := range numbers1 {               // range子句迭代切片汇总的所以元素值
    if i == 3 {
    numbers1[i] |= i
    }
}
fmt.Println(numbers1)

for语句被执行的时候,range关键字右边(range表达式)的numbers1会被先求值,range表达式的结果可以是数组、数组的指针、切片、字符串、字典或允许接收操作的通道中的某一个,并且结果只能有一个。

对于不同种类的range表达式结果值,for语句的迭代变量的数量可以有所不同。上述切片的的迭代变量可以有两个,切片中的索引值和迭代对应的某一个值。

当range表达式只有一个迭代变量的时候,数组、数组的指针、切片、字符串的元素值都是无处安放的,只能按照从小到大的顺序给出一个个索引值。

注意

numbers2 := [...]int{1, 2, 3, 4, 5, 6}      // munbers2是数组,为值类型
maxIndex2 := len(numbers2) - 1
for i, e := range numbers2 {
    if i == maxIndex2 {
        numbers2[0] += e
    } else {
        numbers2[i+1] += e
    }
}
fmt.Println(numbers2)
  1. range表达式只会在for语句开始执行时被求值一次,无论后面有多少其他操作
  2. range表达式的求值结果会被复制,被操作的对象是range表达式结果的副本而不是原值
numbers3 := []int{1, 2, 3, 4, 5, 6}     // mumber3是切片,为引用类型
maxIndex3 := len(numbers3) - 1
for i, e := range numbers3 {
    if i == maxIndex2 {
        numbers3[0] += e
    } else {
        numbers3[i+1] += e
    }
}
fmt.Println(numbers3)
  1. range表达式只会在for语句开始执行时被求值一次,无论后面有多少其他操作
  2. range表达式的求值结果的引用会被复制,被操作的对象是range表达式结果的原值

switch表达式和case表达式的联系

只有switch表达式的结果值与某个case表达式中的任意一个子表达式的结果值相等,该case表达式所属的case子句就会被选中,case子句被选中后,附带在case表达式后边的语句会被执行,其他case子句会被忽略。

value1 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch 1 + 3 {                       // switch表达式,结果值为无类型常量时,自动转换为此常量值默认的类型
case value1[0], value1[1]:           // case表达式,case表达式中的结果值与switch表达式中的结果值类型不同
    fmt.Println("0 or 1")
case value1[2], value1[3]:
    fmt.Println("2 or 3")
case value1[4], value1[5], value1[6]:
    fmt.Println("4 or 5 or 6")
}

在case子句附带的语句列表中包含fallthrough语句,那么紧挨在它下边的那个case自己附带的语句也会被执行

因为存在上述判等操作,对switch表达式的结果类型和case表达式的结果类型有要求。

  1. 如果switch表达式的结果值为无类型常量,case表达式的结果值为其他类型,无法通过编译
  2. 如果case表达式的结果值为无类型常量,且与switch表达式的结果值类型不同,那么会自动转换为switch表达式的结果值的类型

如果表达式的结果类型有某个接口类型,那么一定要检查他们的动态值是否具有可比性

switch语句对case表达式的约束

结果值为常量的情况下

switch语句在case子句的选择上具有唯一性,因此不允许case表达式结果值存在相等的情况(不论这些结果值相等的子表达式,是否存在于不同的case表达式中)。

// 无法通过编译
value5 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value5[4] {
case value5[0], value5[1], value5[2]:
    fmt.Println("0 or 1 or 2")
case value5[2], value5[3], value5[4]:
    fmt.Println("2 or 3 or 4")
case value5[4], value5[5], value5[6]:
    fmt.Println("4 or 5 or 6")
}

// 可以通过编译
value5 := [...]int8{0, 1, 2, 3, 4, 5, 6}
switch value5[4] {
case value5[0], value5[1], value5[2]:
    fmt.Println("0 or 1 or 2")
case value5[2], value5[3], value5[4]:
    fmt.Println("2 or 3 or 4")
case value5[4], value5[5], value5[6]:
    fmt.Println("4 or 5 or 6")
}

上述第二种方式对类型判断switch语句无效。

类型switch语句

类型switch语句中的case表达式的子表达式,都必须直接由类型字面量表示,而无法通过间接的方式表示。

value6 := interface{}(byte(127))
switch t := value6.(type) {             // 类型switch语句
case uint8, uint16:
    fmt.Println("uint8 or uint16")
case byte:                              // byte为unit8的别名类型,无法通过编译
    fmt.Printf("byte")
default:
    fmt.Printf("unsupported type: %T", t)
}

case子句的编写顺序很重要,最上边的case子句中的子表达式总是会被最先求值,在判等的时候顺序也是这样。因此,如果某些case表达式的结果值有重复,那么位置靠上的case子句总会被选中。

上次修改: 25 November 2019