目录
文章目录
条件判断
if/else 语句
示例:
package main
import "fmt"
func main() {
/* 局部变量定义 */
var a int = 100;
/* 判断布尔表达式 */
if a < 20 {
/* 如果条件为 true 则执行以下语句 */
fmt.Printf("a 小于 20\n" );
} else {
/* 如果条件为 false 则执行以下语句 */
fmt.Printf("a 不小于 20\n" );
}
fmt.Printf("a 的值为 : %d\n", a);
}
可见,Golang 中的条件表达式不需要使用 “()” 括起来。
switch 语句
switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
与 C 语言不通,Golang 中的 switch 匹配项后面也不需要再加 break 语句。switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case。如果我们需要执行后面的 case,可以使用 fallthrough 语句。
格式:
switch var1 {
case val1:
...
case val2:
...
default:
...
}
其中,变量 var1 可以是任何类型,而 val1 和 val2 则是同类型的任意值,类型不被局限于常量或整数,但必须是相同的类型。或者最终结果为相同类型的表达式。如果希望通过布尔数据类型来进行判定,则 switch 关键字后不需要紧跟条件表达式。
同时,还可以同时测试多个可能符合条件的值,使用逗号分割它们,例如:case val1, val2, val3
。
示例:
package main
import "fmt"
func main() {
/* 定义局部变量 */
var grade string = "B"
var marks int = 90
switch marks {
case 90:
grade = "A"
case 80:
grade = "B"
case 50,60,70 :
grade = "C"
default:
grade = "D"
}
switch {
case grade == "A" :
fmt.Printf("优秀!\n" )
case grade == "B", grade == "C" :
fmt.Printf("良好\n" )
case grade == "D" :
fmt.Printf("及格\n" )
case grade == "F":
fmt.Printf("不及格\n" )
default:
fmt.Printf("差\n" );
}
fmt.Printf("你的等级是 %s\n", grade );
}
fallthrough 语句
在 switch 中使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。
示例:
package main
import "fmt"
func main() {
switch {
case false:
fmt.Println("1、case 条件语句为 false")
fallthrough
case true:
fmt.Println("2、case 条件语句为 true")
fallthrough
case false:
fmt.Println("3、case 条件语句为 false")
fallthrough
case true:
fmt.Println("4、case 条件语句为 true")
case false:
fmt.Println("5、case 条件语句为 false")
fallthrough
default:
fmt.Println("6、默认 case")
}
}
结果:
2、case 条件语句为 true
3、case 条件语句为 false
4、case 条件语句为 true
type-switch 语句
Golang 中,还可以使用 type-switch 来判断某个 interface(接口)变量中实际存储的变量类型。
格式:
switch x.(type) {
case type:
statement(s);
case type:
statement(s);
/* 你可以定义任意个数的case */
default: /* 可选 */
statement(s);
}
示例:
package main
import "fmt"
func main() {
var x interface{}
switch i := x.(type) {
case nil:
fmt.Printf(" x 的类型 :%T", i)
case int:
fmt.Printf("x 是 int 型")
case float64:
fmt.Printf("x 是 float64 型")
case func(int) float64:
fmt.Printf("x 是 func(int) 型")
case bool, string:
fmt.Printf("x 是 bool 或 string 型" )
default:
fmt.Printf("未知型")
}
}
select(开关)语句
select 语句类似于用于通信的 switch 语句。区别在于 select 语句是专为 channel(通道)而设计的,每个 case 必须是一个通信操作,要么是发送(ch <- )要么是接收(<- ch)。
select 随机执行一个可运行的 case。如果没有可运行的 case,它将阻塞,直到有 case 可运行。其中,default 子句应该总是可运行的。
- 每个 case 都必须是一个通信操作(communication clause)。
- 所有 channel 表达式都会被求值。
- 所有被发送的表达式都会被求值。
- 如果任意某个通信可以进行,它就执行,其他则被忽略。
- 如果有多个 case 都可以运行,select 会随机公平地选出一个执行。其他不会执行。否则:
- 如果有 default 子句,则执行该语句。
- 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Golang 不会重新对 channel 或值进行求值。
格式:
elect {
case communication clause:
statement(s);
case communication clause:
statement(s);
/* 你可以定义任意数量的 case */
default: /* 可选 */
statement(s);
}
示例:
package main
import "fmt"
func main() {
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
}
简而言之,select 会循环检测所有 case 的条件表达式,如果有满足则执行并退出,否则一直循环检测。
package main
import (
"fmt"
"time"
)
func Chann(ch chan int, stopCh chan bool) {
var i int
i = 10
for j := 0; j < 10; j++ {
ch <- i
time.Sleep(time.Second)
}
stopCh <- true
}
func main() {
ch := make(chan int)
c := 0
stopCh := make(chan bool)
go Chann(ch, stopCh)
for {
select {
case c = <- ch:
fmt.Println("Recvice c:", c)
fmt.Println("channel")
case s := <- ch:
fmt.Println("Receive s:", s)
case _ = <- stopCh:
goto end
}
}
end:
}
结果:
Recvice c: 10
channel
Receive s: 10
Recvice c: 10
channel
Receive s: 10
Receive s: 10
Recvice c: 10
channel
Receive s: 10
Receive s: 10
Recvice c: 10
channel
Recvice c: 10
channel
循环
for 循环语句
Golang 仅支持 for 循环,但 Golang 的 for 循环具有 3 种形式。
- 和 C 语言的 for 一样,但循环控制语句不需要使用 “()” 括起来:
for init; condition; post { }
- init:一般为赋值表达式,给控制变量赋初值;
- condition:关系表达式或逻辑表达式,循环控制条件;
- post:一般为赋值表达式,给控制变量增量或减量。
for 循环的执行过程如下:
- 先对 init 赋初值;
- 判别赋值表达式 init 是否满足 condition 条件,若其值为真,则执行循环体内语句,然后执行 post。进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止 for 循环,执行循环体外语句。
示例:计算 1 到 10 的数字之和
package main
import "fmt"
func main() {
sum := 0
for i := 0; i <= 10; i++ {
sum += i
}
fmt.Println(sum)
}
- 和 C 的 while 循环一样,省略 init 和 post:
for condition { }
示例:
package main
import "fmt"
func main() {
sum := 1
for sum <= 10 {
sum += sum
}
fmt.Println(sum)
}
- 和 C 的
for(;;)
一样,省略 init、condition 和 post:
for { }
示例,无限循环
package main
import "fmt"
func main() {
sum := 0
for {
sum++ // 无限循环下去
}
fmt.Println(sum) // 无法输出
}
For-each range 循环语句
Golang 提供了 range(范围)关键字,用于 for 循环中迭代字符串、数组(Array)、切片(Slice)、通道(Channel)或集合(Map)中所含有的元素。
- 数组、切片:返回元素的索引和索引对应的值
- 集合:返回 key/value 对。
格式:
for key, value := range oldMap {
newMap[key] = value
}
示例:For-each range 循环,这种格式的循环可以对 Slice、Map、数组、字符串进行迭代输出各个元素。
package main
import "fmt"
func main() {
// 定义数组
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
// 定义数组
numbers := [6]int{1, 2, 3, 5}
for i, x := range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
}
结果:
0 google
1 runoob
第 0 位 x 的值 = 1
第 1 位 x 的值 = 2
第 2 位 x 的值 = 3
第 3 位 x 的值 = 5
第 4 位 x 的值 = 0
第 5 位 x 的值 = 0
示例:
package main
import "fmt"
func main() {
// 这是我们使用 range 去求一个 slice 的和,使用数组跟这个很类似。
nums := []int{2, 3, 4}
sum := 0
// 在数组上使用 range 将传入 index 和 value 两个变量。
// 上面那个例子我们不需要使用该元素的序号,所以我们使用空白符 _ 省略了。有时侯我们确实需要知道它的索引。
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
// range 也可以用在 map 的键值对上。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
// range 也可以用来枚举 Unicode 字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
for i, c := range "go" {
fmt.Println(i, c)
}
}
结果:
sum: 9
index: 1
a -> apple
b -> banana
0 103
1 111
循环控制语句
break 语句
- 用于循环语句中跳出循环,并开始执行循环之后的语句。
- break 在 switch 语句中在执行一条 case 后跳出。
- 在多重循环中,可以用标号 label 标出想跳出的循环。
示例:
package main
import "fmt"
func main() {
// 不使用 label 标记
fmt.Println("---- break ----")
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break
}
}
// 使用 label 标记,常见于跳出潜逃循环。
fmt.Println("---- break label ----")
re:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break re
}
}
}
continue 语句
与 breck 不同,continue 不是跳出循环,而是跳过当前循环并执行下一次循环。所以,在 for 循环中,执行 continue 语句同样会触发 for 增量语句的执行。
在多重循环中,同样可以用标号 label 标出想 continue 的循环。
示例:
package main
import "fmt"
func main() {
// 不使用 label 标记
fmt.Println("---- continue ---- ")
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue
}
}
// 使用标记
fmt.Println("---- continue label ----")
re:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue re
}
}
}
goto 语句
与 C 语言类似的,goto 语句可以无条件地转移到过程中指定的行。goto 语句通常与条件语句配合使用。可用来实现条件转移,构成循环,跳出循环体等功能。
通常的,在结构化程序设计中一般不主张使用 goto 语句,以免造成程序流程的混乱,使理解和调试程序都产生困难。
格式:
goto label;
..
.
label:
statement(s);
示例:在变量 a 等于 15 的时候跳过本次循环并回到循环的开始语句 LOOP 处
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* 循环 */
LOOP: for a < 20 {
if a == 15 {
/* 跳过迭代 */
a = a + 1
goto LOOP
}
fmt.Printf("a的值为 : %d\n", a)
a++
}
}