写在前面:
0x01 — if语句
if是程序中最常用的,这里简单介绍下,在Golang中需要注意的是,由于Golang语言函数的多返回值的特性,所以我们经常将表达式写在if语句中,通过分号(;)分割语句,这算是一个比较有特色的功能:
package main
import (
"errors"
"testing"
)
// 此函数根据输入进行返回
func test(r int) (int,error){
if r == 0 {
return r, errors.New("false")
} else if r == 1 {
return r, nil
} else {
return r * r, nil
}
}
func TestIf(t *testing.T) {
if _,err := test(0); err != nil { // 通过_来获取不使用的变量
t.Log("返回值:", err)
} else {
t.Log("返回值为true")
}
if res,err := test(1); err != nil {
t.Log("返回值:", err)
} else {
t.Log("平方值:", res)
}
if res,err := test(3); err != nil {
t.Log("返回值:", err)
} else {
t.Log("平方值:", res)
}
}
输出:
=== RUN TestIf
condition_test.go:21: 返回值: false
condition_test.go:28: 平方值: 1
condition_test.go:33: 平方值: 9
--- PASS: TestIf (0.00s)
PASS
0x02 — switch
在golang中,Switch和其他语言使用方式一样,基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止,区别在于,在匹配后执行地完成的语句中不需要再进行break,默认会自动跳出,如果想要继续执行后面的语句,需要显示声明关键字 fallthrough :
package main
import (
"errors"
"testing"
)
func TestSwitch(t *testing.T) {
var even, odd []int
for i := 0; i < 20;i++ {
switch i % 2 { // 这里可以是表达式,
case 0: // case中的值类型必须是switch表达式中计算的类型
even = append(even, i)
case 1:
odd = append(odd, i)
default:
t.Log("无效的自然数")
}
}
t.Log("奇数:", odd)
t.Log("偶数:", even)
}
输出:
=== RUN TestSwitch
condition_test.go:20: 奇数: [1 3 5 7 9 11 13 15 17 19]
condition_test.go:21: 偶数: [0 2 4 6 8 10 12 14 16 18]
--- PASS: TestSwitch (0.00s)
PASS
如果增加了fallthrough的话,看下面的例子:
package main
import (
"errors"
"testing"
)
func TestSwitch(t *testing.T) {
var even, allNum []int
for i := 0; i < 20;i++ {
switch i % 2 { // 这里可以是表达式,
case 0: // case中的值类型必须是switch表达式中计算的类型
even = append(even, i)
fallthrough
case 1:
allNum = append(allNum, i)
default:
t.Log("无效的自然数")
}
}
t.Log("奇数:", allNum)
t.Log("偶数:", even)
}
输出:
=== RUN TestSwitch
condition_test.go:21: 奇数: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
condition_test.go:22: 偶数: [0 2 4 6 8 10 12 14 16 18]
--- PASS: TestSwitch (0.00s)
PASS
case可以接收多个匹配值:case 1,2,3,4 匹配到其中一个则会执行当前case下的语句
0x03 — select
select 是 Golang 中间的一个通信控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。
如果只有一个case被触发,则会执行对应case的语句,如果多个case被触发,select 随机执行一个可运行的任务 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。如果存在default,则不会阻塞,会执行default中语句:
package main
import (
"errors"
"fmt"
"testing"
"time"
)
func connectServer(t *time.Ticker, c,d chan<- int){
var count int
for _ = range t.C {
count += 1
fmt.Printf("正在进行第%d次连接...\n", count)
if count == 3 {
c <- 1 // 如果对c通道进行发送,select中的c通道则会接收,并执行下面的语句
//d <- 1 // 如果对d通道进行发送,select中的c通道则会接收,并执行下面的语句
}
}
}
func TestSelect(t *testing.T) {
status := make(chan int)
abort := make(chan int)
ticker := time.NewTicker(time.Second * 1) // ticker是时间包中的一个轮询函数,会按时间持续即时,可用于心跳等
go connectServer(ticker, status, abort)
select {
case <-status:
t.Log("连接成功")
case <-abort:
t.Log("无法连接,断开")
}
ticker.Stop() // 停止轮询
}
输出:
=== RUN TestSelect
正在进行第1次连接...
正在进行第2次连接...
正在进行第3次连接...
condition_test.go:28: 连接成功
--- PASS: TestSelect (3.00s)
PASS
我们对上面的代码进行改进一下:
package main
import (
"errors"
"fmt"
"testing"
"time"
)
func connectServer(t *time.Ticker, c chan<- int){
var count int
for _ = range t.C {
count += 1
fmt.Printf("正在进行第%d次连接...\n", count)
if count == 5 {
c <- 1 // 如果对c通道进行发送,select中的c通道则会接收,并执行下面的语句
}
}
}
func TestSelect(t *testing.T) {
status := make(chan int)
//abort := make(chan int)
ticker := time.NewTicker(time.Second * 1) // ticker是时间包中的一个轮询函数,会按时间持续即时,可用于心跳等
go connectServer(ticker, status)
select {
case <-status:
t.Log("连接成功")
case <-time.After(time.Second * 3):// time.After函数是会在多久后返回一个通道值,用于超时很友好
t.Log("无法连接,断开")
}
ticker.Stop() // 停止轮询
}
输出:
=== RUN TestSelect
正在进行第1次连接...
正在进行第2次连接...
正在进行第3次连接...
condition_test.go:30: 无法连接,断开
--- PASS: TestSelect (3.00s)
PASS
0x04 — 总结
有不明白的可以评论区留言,看到一定及时回复。