程序代码很多时候就是对现实的表达,比如买一个东西,要看你有没有带够钱,这种逻辑关系就是判断条件。
//CanBuy 判断钱是否足够
func CanBuy(hasMoney, productPrice int) {
// if 后面不需要括号,if 的执行体无论是否为空 { } 都是必须的
if hasMoney >= productPrice {
fmt.Printf("you can, will %d left", hasMoney-productPrice)
}
}
if 满足的时候执行 if 的函数体,如果不满足需要执行还可以跟一个 else 语句,如果还有判断可以接 else if 语句。
if 天不下雨 {
// 出去吃
} else if 有肉和菜 {
// 将就吃
} else {
// 点外卖
}
注意 go 语言的 if 不需要括号 (),而 if 后面的执行体总是需要括号 {},if 里可以嵌套 if,但是写代码的时候应该放置嵌套过深,if 虽然好用但是会增加代码的复杂度,下面几个函数,你觉得哪个会好一点呢?
//CheckPrice1 判断贵不贵
func CheckPrice1(amount int) {
if amount > 50 {
if amount > 100 {
fmt.Println("太贵了")
} else {
fmt.Println("还行")
}
} else {
fmt.Println("真便宜啊")
}
}
//CheckPrice2 判断贵不贵
func CheckPrice2(amount int) {
if amount > 50 {
if amount > 100 {
fmt.Println("太贵了")
} else {
fmt.Println("还行")
}
return
}
fmt.Println("真便宜啊")
}
//CheckPrice3 判断贵不贵
func CheckPrice3(amount int) {
if amount > 100 {
fmt.Println("太贵了")
} else if amount > 50 {
fmt.Println("还行")
} else {
fmt.Println("真便宜啊")
}
}
//CheckPrice4 判断贵不贵
func CheckPrice4(amount int) {
if amount <= 50 {
fmt.Println("真便宜啊")
return
}
if amount > 50 && amount <= 100 {
fmt.Println("还行")
} else {
fmt.Println("太贵了")
}
}
//CheckPrice5 判断贵不贵
func CheckPrice5(amount int) {
if amount > 100 {
fmt.Println("太贵了")
return
}
if amount > 50 {
fmt.Println("还行")
return
}
fmt.Println("真便宜啊")
}
你可能学过 C 语言的三目运算符,觉得它们看起来都不太好,不过 go 不支持三目运算符,因为三目运算符能写出非常复杂的代码。就目前学习的知识点来看,版本 checkPrice5 相对来讲没有过多的嵌套的层级,使用 if 的时候要特别注意这个代码复杂度的问题。
除了判断,就是循环,for 循环可以指定执行的次数,完整的 for 循环是:
// FullFor 完整的 for 定义
func FullFor() {
sum := 0
// 初始值; 循环条件; 增量/减量
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
初始值和增减量是可以没有,这时候两边的分号也可以不写了。
// ConditionFor 只有循环条件
func ConditionFor() {
sum := 1
// for ; sum < 10 ; {
for sum < 10 {
sum += sum
}
fmt.Println(sum)
}
如果连循环条件也没有,那就是死循环了,一直出不来,你需要用 ctrl + c 或者 kill 来结束掉进程,在一个中如果出现死循环往往是致命的,可能导致 CPU 超级高,但是程序本身并没有做什么有意义的事情。
// DeadFor 死循环
func DeadFor() {
for true {
// 无限循环
}
for {
// 无限循环
}
}
for 循环的过程,可以使用 continue 来跳过当次循环,使用 break 中断循环。
//BreakContinueFor 跳过和中断
func BreakContinueFor() {
for i := 0; i < 100; i++ {
// 余数是 0 是偶数,跳过
if i%2 == 0 {
continue
}
// 大于 10 就中断循环
if i > 10 {
break
}
fmt.Printf("%d ", i)
}
fmt.Println()
}
for-range 用来迭代字符串、数组、切片等类型,index 是迭代的索引,类似循环变量,ch 是拷贝的迭代值,for-range 有一些要注意的知识点和坑,以后会经常用到它。
// ForRange 安全的迭代循环
func ForRange() {
str := "this is a test"
for index, ch := range str {
// 跳过空格不处理
if ch != 0x20 {
fmt.Printf("%d%c ", index, ch)
}
}
fmt.Println()
}
如果不关心循环的具体值,可以不写 for-range 的第二个循环变量。
// ForRange2 安全的迭代循环
func ForRange2() {
str := "this is a test"
for index := range str {
fmt.Printf("%d ", index)
}
fmt.Println()
}
如果不关心循环的次数,index 却不能不写,但是可以使用 _ 占位符来代替,表示不关心它具体的值。
// ForRange3 安全的迭代循环
func ForRange3() {
str := "this is a test"
for _, ch := range str {
fmt.Printf("%c", ch)
}
fmt.Println()
}
switch-case 用于不同的条件执行不同的动作,每个 case 都是一个分支,挨个比对值,如果匹配就执行对应的分支,后面的分支不再测试,注意 case 分支不需要加 break。
// FullSwitch 挨个顺序匹配
func FullSwitch(rank string) {
switch rank {
case "gold":
fmt.Println("1st")
case "silver", "bronze":
fmt.Println("2nd or 3rd")
default:
// 匹配不到才会执行
fmt.Println("未获奖")
}
}
switch-case 有个特殊的 fallthrough 用法,它会无条件的执行匹配到的下一个case。
// FallThrough 执行匹配到下一个 case 语句(无论它的条件是真是假)
func FallThrough() {
switch {
case true:
fmt.Println("我是匹配到的")
fallthrough
case false:
fmt.Println("虽然我是 false,但我会被打印")
fallthrough
case false:
fmt.Println("虽然我也是 false,但我也会被打印")
// fallthrough
// 如果放开这个 fallthrough,下面的 default 也会被执行
default:
fmt.Println("放开上面的 fallthrough 才能看到我")
}
}
goto 语句可能被认为是洪水猛兽,因为滥用 goto 可能是程序的逻辑变得混乱,go 语言支持 goto 语句,需要一个 label 来配合申明,下面的代码使用 goto 跳出 3 层 for 循环,如果使用 if + break 需要做标记变量层层判断(break 不能中断外层的循环体),使用 goto 简化了代码复杂度。
//JumpOutside 使用 goto 跳出多层循环
func JumpOutside() {
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
for k := 0; k < 10; k++ {
fmt.Println(i, j, k)
if i == 1 && j == 2 && k == 3 {
goto GAMEOVER
}
}
}
}
GAMEOVER:
fmt.Println("game over")
}
select 分支语句是 go 语言非常重要的分支判断语句,在学了通道以后会用的特别多,也是有别于其他语言的一个语法。select 带有多个 case,每个 case 都是一个 IO 操作,select 随机的选择满足条件的执行一个,重点来了,如果没有 case 可以运行,它将发生阻塞,一直等到有一个 case 满足条件位置。所以下面的代码是一个死循环,一直会阻塞,因为它没有 case,永远都不会满足一个。
// DeadSelect 一直阻塞
func DeadSelect() {
select {}
}
由于我们还没有学习关于通道的知识,本节暂时略过 select 语句,它非常重要,在学习通道的时候会详细讲解它的用法。
本章节的代码