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

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

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条件,这部分内容会在后续接口部分的笔记介绍。

往期内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值