红茶的个人站点

  • 首页
  • 专栏
  • 开发工具
  • 其它
  • 隐私政策
Awalon
Talk is cheap,show me the code.
  1. 首页
  2. 专栏
  3. Go语言编程笔记
  4. 正文

Go语言编程笔记3:控制流

2021年11月7日 1115点热度 0人点赞 0条评论

img

图源:2zyyyyy.github.io

一般来说,不同的编程语言之间控制流语句的差别应该是很小的,但Go语言的控制流语句有很多不同之处,值得单独进行讨论。

if

除了和其它语言类似的写法以外,Go语言可以在if语句的条件中添加赋值语句:

package main
​
import "fmt"
​
func main() {
    if a := 6; a < 10 {
        fmt.Println("a<10")
    }
}

当然上边这段示例的写法是没必要的,更常见的是通过函数调用获取结果后进行判断:

package main
​
import (
    "fmt"
    "log"
    "strconv"
)
​
func main() {
    checkStringNumber("12")
    checkStringNumber("2.5")
    checkStringNumber("lalala")
}
​
func checkStringNumber(strA string) {
    if floatA, err := strconv.ParseFloat(strA, 64); err != nil {
        log.Fatal(err)
    } else if floatA > 10 {
        fmt.Println("a>10")
    } else {
        fmt.Println("a<=10")
    }
}
​
// a>10
// a<=10
// 2021/11/07 15:38:50 strconv.ParseFloat: parsing "lalala": invalid syntax

当然这种方式只是给你提供了一种选择,并非必须,不过这么做可能带来的好处就是,将通过函数调用的返回值的使用范围局限到一个if语句的作用域内,而不会污染外部的函数作用域。如果你遇到一些变量命名冲突的问题可以尝试用这种方式解决。

此外,Go语言对一些格式有严格要求,比如常见的if...else写法:

package main
​
import "fmt"
​
func main() {
    if 1 < 5 {
        fmt.Println("1<5")
    }
    else{
        fmt.Println("1>=5")
    }
}

在Go语言中是不允许的,因为Go要求else必须要和if块的}符号在同一行:

package main
​
import "fmt"
​
func main() {
    if 1 < 5 {
        fmt.Println("1<5")
    } else {
        fmt.Println("1>=5")
    }
}

怎么说呢,我一直都用的不允许的那种书写风格...我只能说,Go语言的作者大概是个强迫症吧。

顺带一提,Go语言中是可以给if语句中的条件表达式加上()的,但没必要,因为官方的格式化工具会在格式化代码时强制将不必要的()删除,你大概会写了个寂寞。

for

Go语言中只有for语句用于循环,没有while语句。此外for也仅有一种形式,即最经典的for 循环变量初始化;循环条件;循环变量步进。

这里展示一个实际例子:

package main
​
import "fmt"
​
func main() {
    for i := 0; i < 10; i++ {
        fmt.Printf("%d ", i)
    }
    fmt.Println()
}
​
// 0 1 2 3 4 5 6 7 8 9

特别的,可以将循环变量初始化和步进语句省略,在这种情况下for循环更像是其它语言中的while语句:

package main
​
import "fmt"
​
func main() {
    i := 0
    for i < 10 {
        fmt.Printf("%d ", i)
        i++
    }
    fmt.Println()
}
​
// 0 1 2 3 4 5 6 7 8 9

此时i<10左右两侧的;写不写都一样,格式化工具会自动删除,所以最好还是别写。

甚至可以完全删除for所有的三个表达式:

package main
​
import "fmt"
​
func main() {
    i := 0
    for {
        if i >= 10 {
            break
        }
        fmt.Printf("%d ", i)
        i++
    }
    fmt.Println()
}
​
// 0 1 2 3 4 5 6 7 8 9

此时的for语句事实上就是一个无限循环语句,除非使用break跳出,否则会一直循环下去。

其它比较常见的用法还有结合range关键字来迭代数组或切片:

package main
​
import "fmt"
​
func main() {
    numbers := []int{1, 2, 3, 4, 5, 6}
    for index, value := range numbers {
        fmt.Printf("numbers[%d]=%d\n", index, value)
    }
}
​
// numbers[0]=1
// numbers[1]=2
// numbers[2]=3
// numbers[3]=4
// numbers[4]=5
// numbers[5]=6

通道也可以使用这种方式来迭代,关于通道,会在后边介绍。

for语句的作用域问题也是个会容易忽视的问题,该内容已经在之前Go语言编程笔记2:变量中讨论过了,这里不再赘述。

switch

表面上看Go语言的switch语句与其它语言类似,其实有很大的不同:

package main
​
import "fmt"
​
func main() {
    login("lalala")
    login("root")
    login("apple")
}
​
func login(name string) {
    switch name {
    case "apple":
        fmt.Println("welcome")
    case "root":
        fmt.Println("don't permit use root account login")
    default:
        fmt.Println("it's a unregistry account")
    }
}
​
// it's a unregistry account
// don't permit use root account login
// welcome

看上去似乎除了没有使用break以外和其它语言的switch语句差别不大,但其实有很大差别。

一般性的switch语句的执行流程是依次匹配所有的case条件,如果满足就执行相应的case块,执行过程中如果有break语句就跳出switch,如果没有,在结束case块后会继续switch的逻辑向下匹配。

但Go语言中的switch不会,它会像自带break那样,一旦匹配到某个case条件,执行完相应的case块,就会结束整个switch语句。

此外,我们依然是可以在switch中显式地执行break的:

package main
​
import "fmt"
​
func main() {
    login("lalala")
    login("root")
    login("apple")
}
​
func login(name string) {
    switch name {
    case "apple":
        break
        fmt.Println("welcome")
    case "root":
        fmt.Println("don't permit use root account login")
    default:
        fmt.Println("it's a unregistry account")
    }
}
​
// it's a unregistry account
// don't permit use root account login

Go语言的switch语法中还有一个奇怪的关键字fallthrough:

package main
​
import "fmt"
​
func main() {
    login("lalala")
    login("root")
    login("apple")
}
​
func login(name string) {
    switch name {
    case "apple":
        fmt.Println("welcome")
        fallthrough
    case "root":
        fmt.Println("don't permit use root account login")
    default:
        fmt.Println("it's a unregistry account")
    }
}
​
// it's a unregistry account
// don't permit use root account login
// welcome
// don't permit use root account login

如果在某个case块的结尾使用fallthrough,程序会自动跳转到下一个case块中执行,无论下一个case块的匹配条件是什么。我并不清楚这个关键字在实际工作中有什么使用场景,所以这里不过多讨论。

除了一般性的利用switch进行值匹配外,switch还可以检测变量的类型:

package main
​
import "fmt"
​
func main() {
    checkType("hello")
    checkType("1")
    checkType(1)
    checkType(2.5)
}
​
func checkType(variable interface{}) {
    var varForm string
    switch variable.(type) {
    case int:
        varForm = "int"
    case float64, float32:
        varForm = "float"
    case string:
        varForm = "string"
    default:
        varForm = "not known"
    }
    fmt.Printf("%v 's type is %s\n", variable, varForm)
}
​
// hello 's type is string
// 1 's type is string
// 1 's type is int
// 2.5 's type is float

特别的,如果用switch匹配多个接口类型,是有可能同时满足多个接口的,此时应当遵循“先精细后粗略”的顺序排布case条件,这部分内容会在后续接口部分的笔记介绍。

往期内容

  • Go语言编程笔记2:变量

  • Go语言编程笔记1:Hello World

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: Go语言
最后更新:2021年11月22日

魔芋红茶

加一点PHP,加一点Go,加一点Python......

点赞
< 上一篇
下一篇 >

文章评论

取消回复

*

code

COPYRIGHT © 2021 icexmoon.cn. ALL RIGHTS RESERVED.
本网站由提供CDN加速/云存储服务

Theme Kratos Made By Seaton Jiang

宁ICP备2021001508号

宁公网安备64040202000141号