if-else
语句模型
if 条件 1 {
分支 1
} else if 条件 2 {
分支 2
} else if 条件 … {
分支 …
} else {
分支 else
}
单分支
age := 20
gender := "male"
if (age > 18 && gender == "male") {
fmt.Println("是成年男性")
}
多分支
age := 20
if age > 18 {
fmt.Println("已经成年了")
} else if age >12 {
fmt.Println("已经是青少年了")
} else {
fmt.Println("还不是青少年")
}
高级写法
if age >=18;sex == "男"{
fmt.Println("成年人就该做成年人应该的事情")
}
switch-case
语句模型
switch 表达式 {
case 表达式1:
代码块
case 表达式2:
代码块
case 表达式3:
代码块
case 表达式4:
代码块
case 表达式5:
代码块
default:
代码块
}
1、简单示例
func main() {
education := "本科"
switch education {
case "博士":
fmt.Println("我是博士")
case "研究生":
fmt.Println("我是研究生")
case "本科":
fmt.Println("我是本科生")
case "大专":
fmt.Println("我是大专生")
case "高中":
fmt.Println("我是高中生")
default:
fmt.Println("学历未达标..")
}
}
2、一个case多个条件
import "fmt"
func main() {
month := 2
switch month {
case 3, 4, 5:
fmt.Println("春天")
case 6, 7, 8:
fmt.Println("夏天")
case 9, 10, 11:
fmt.Println("秋天")
case 12, 1, 2:
fmt.Println("冬天")
default:
fmt.Println("输入有误...")
}
}
3、case条件常量不能重复
4、switch后可接函数
import "fmt"
// 判断一个同学是否有挂科记录的函数
// 返回值是布尔类型
func getResult(args ...int) bool {
for _, i := range args {
if i < 60 {
return false
}
}
return true
}
func main() {
chinese := 80
english := 50
math := 100
switch getResult(chinese, english, math) {
// case 后也必须 是布尔类型
case true:
fmt.Println("该同学所有成绩都合格")
case false:
fmt.Println("该同学有挂科记录")
}
}
5、可不接表达式,当作if-else使用
score := 30
switch {
case score >= 95 && score <= 100:
fmt.Println("优秀")
case score >= 80:
fmt.Println("良好")
case score >= 60:
fmt.Println("合格")
case score >= 0:
fmt.Println("不合格")
default:
fmt.Println("输入有误...")
}
6、swithc穿透能力
s := "hello"
switch {
case s == "hello":
fmt.Println("hello")
fallthrough
case s != "world":
fmt.Println("world")
}
fallthrough 只能穿透一层,意思是它让你直接执行下一个case的语句,而且不需要判断条件。
for循环
for循环的基本模型
for [condition | ( init; condition; increment ) | Range]
{
statement(s);
}
for后面可以接4种类型的表达式
1、接一个条件表达式
a := 1
for a <= 5{
fmt.Println(a)
a++
}
2、接三个条件表达式
for i := 0; i <= 5; i++{
fmt.Println(i)
}
3、接一个range表达式
myarr := [...]string{"hello","world","!"}
for _, item := range myarr{
fmt.Printf("heool,%s\n",item)
}
4、不接表达式(无限循环)
var i int = 1
for {
if i > 5 {
break
}
fmt.Printf("hello, %d\n", i)
i++
}
goto无条件跳转
基本模型
goto 标签;
…
…
标签: 表达式;
1、最简单示例
import "fmt"
func main(){
goto flag
fmt.Println("B")
flag:
fmt.Println("A")
}
输出
A
如何是用?
通常是与条件语句配合使用,可以用来实现条件转移,构成循环,跳出循环体的功能
func main(){
i :=1
flag:
if i == 5{
fmt.Println(i)
i++
goto flag
}
}
func main(){
i := 1
for {
if i >=5{
goto flag
}
fmt.Println(i)
i++
}
flag:
}
goto语句与标签之间不能有变量声明,否则编译错误
defer延迟语句
先进后出原则
import "fmt"
func main() {
name := "go"
defer fmt.Println(name) // 输出: go
name = "python"
defer fmt.Println(name) // 输出: python
name = "java"
fmt.Println(name)
}
输出
java
python
go
defer 和 return 谁先执行
import "fmt"
var name string = "go"
func myfunc() string {
defer func() {
name = "python"
}()
fmt.Printf("myfunc 函数里的name:%s\n", name)
return name
}
func main() {
myname := myfunc()
fmt.Printf("main 函数里的name: %s\n", name)
fmt.Println("main 函数里的myname: ", myname)
}
输出
myfunc 函数里的name:go
main 函数里的name: python
main 函数里的myname: go
defer 是return 后才调用的。所以在执行 defer 前,myname 已经被赋值成 go 了。
select
仅能用做信道/通道的相关操作
select {
case 表达式1:
case 表达式2:
default:
}
package main
import (
"fmt"
)
func main() {
c1 := make(chan string, 1)
c2 := make(chan string, 1)
c2 <- "hello"
select {
case msg1 := <-c1:
fmt.Println("c1 received: ", msg1)
case msg2 := <-c2:
fmt.Println("c2 received: ", msg2)
default:
fmt.Println("No data received.")
}
}
在运行 select 时,会遍历所有(如果有机会的话)的 case 表达式,只要有一个信道有接收到数据,那么 select 就结束,所以输出如下
c2 received: hello
避免造成死锁,select在执行过程中,必须命中其中的某一分支,如果在遍历完所有的case后,若没有命中,就会进入default里面的代码分支,但如果你没有哦写default分支,select就会阻塞,直到某个case可以命中,而如果一直没有命中,select就会抛出deadlock的错误
随机性,多个信道接收到数据,多个case命中,会随机一个分支执行
select的超时,当case里面的信道始终没有接收到数据时,而且也没有default语句时,select整体就会阻塞,我们可以手动设置一个超时时间避免阻塞
package main
import(
"fmt"
"time"
)
func main(){
c1 := make(chan string,1)
c2 := make(chan string,1)
timeout := make(chan bool,1)
go makeTimeout(timeout,2)
select{
case msg1 := <=c1:
fmt.Println("c1 received:",msg1)
case msg2 := <-c2:
fmt.Println("c2 received:",msg2)
case <-timeout:
fmt.Println("Timeout,exit.")
}
}
读取/写入都可以
select 里的 case 表达式只要求你是对信道的操作即可,不管你是往信道写入数据,还是从信道读出数据。
package main
import (
"fmt"
)
func main() {
c1 := make(chan int, 2)
c1 <- 2
select {
case c1 <- 4:
fmt.Println("c1 received: ", <-c1)
fmt.Println("c1 received: ", <-c1)
default:
fmt.Println("channel blocking")
}
}
输出
c1 received: 2
c1 received: 4
信道关闭也可命中
package main
import "fmt"
func main() {
c1 := make(chan int, 1)
c2 := make(chan int, 1)
close(c1)
for {
select {
case <-c1:
fmt.Println("stop");
return
case <-c2:
fmt.Println("hhh")
}
}
}
$ go run main.go
stop
总结
- select 只能用于 channel 的操作(写入/读出/关闭),而 switch 则更通用一些;
- select 的 case 是随机的,而 switch 里的 case 是顺序执行;
- select 要注意避免出现死锁,同时也可以自行实现超时机制;
- select 里没有类似 switch 里的 fallthrough 的用法;
- select 不能像 switch 一样接函数或其他表达式。