if else
1
2
3
4
5
|
// a == 100不需要加(),否则编译报错
if a == 100 {
...
}
|
switch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
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"
}
// 根据type
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("未知型")
}
// fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。下面输出为:2 3 4
switch {
case false:
fmt.Println("1")
fallthrough
case true:
fmt.Println("2")
fallthrough
case false:
fmt.Println("3")
fallthrough
case true:
fmt.Println("4")
case false:
fmt.Println("5")
fallthrough
default:
fmt.Println("6")
}
}
|
select
select 语句只能用于通道(chan)操作,每个 case 必须是一个通道操作,要么是发送要么是接收。
select 语句会监听所有指定的通道上的操作,一旦其中一个通道准备好就会执行相应的代码块。
如果多个通道都准备好,那么 select 语句会随机选择一个通道执行。如果所有通道都没有准备好,那么执行 default 块中的代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
package main
import (
"fmt"
"time"
)
func main() {
// make(chan string)创建一个传输字符串的通道实例
c1 := make(chan string)
c2 := make(chan string)
/*
make()专门用于初始化三种内建引用类型:切片、映射map、通道channel
*/
// go 表示异步执行这个函数,不阻塞当前程序
// func()表示定义一个匿名函数
// 最后的 () 表示立即调用这个匿名函数
go func() {
time.Sleep(1 * time.Second)
//向c1通道发消息
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
//向c2通道发消息
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
|
循环
Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。
break关键字会终止最内层的for循环。continue关键字会跳过最内层循环的本次迭代。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 和 C 语言的 for 一样:
//for init; condition; post { }
for i := 0; i <= 10; i++ {
sum += i
}
//和 C 的 while 一样只保留循环条件:
//for condition { }
for input != "quit" {
fmt.Print("请输入 (输入 'quit' 退出): ")
fmt.Scanln(&input)
fmt.Println("你输入了:", input)
}
//和 C 的 for(;;) 一样,死循环,永远也不会退出:
//for { }
for {
sum++ // 无限循环下去
}
|
for range 遍历可迭代的数据结构,如数组,切片,字符串,映射表,通道:
1
2
3
4
5
6
|
func main() {
sequence := "hello world"
for index, value := range sequence {
fmt.Println(index, value)
}
}
|
数组和切片
- 数组是定长的数据结构,长度被指定后就不能被改变。在声明时长度只能是一个常量,不能是变量。
切割数组的格式为arr[startIndex:endIndex],切割的区间为左闭右开。数组在切割后,就会变为切片类型,因为右边是开的,长度不确定!
1
2
3
4
5
6
7
8
9
|
var nums [5]int
nums := [5]int{1, 2, 3}
//等价于nums := [5]int{1, 2, 3, 4, 5},省略号必须存在,否则生成的是切片,不是数组
nums := [...]int{1, 2, 3, 4, 5}
// 通过new函数获得一个指针
nums := new([5]int)
|
- 切片是不定长的,切片在容量不够时会自行扩容,切片的初始化方式有以下几种:
1
2
3
4
|
var nums []int /
nums := []int{1, 2, 3}//len = 3, cap = 4
nums := make([]int, 0, 0)
nums := new([]int) // 指针
|
cap指容量,len指元素数量, Go 切片具有自动扩容机制,会将元素容量自动扩到2的幂!
切片的底层实现依旧是数组,是引用类型,可以简单理解为是指向底层数组的指针(本质上切片在Go中是一个结构体,包含指向底层数组的指针、长度值、容量值)。因此切片作为函数参数传递时不复制底层数组,函数内对传入切片的修改会反映在原切片中。
若要将数组转换为切片类型,不带参数进行切片即可,转换后的切片与原数组指向的是同一片内存,修改切片会导致原数组内容的变化,如果要对转换后的切片进行修改,建议使用下面这种方式进行转换:
1
2
3
4
5
6
7
|
func main() {
arr := [5]int{1, 2, 3, 4, 5}
slice := slices.Clone(arr[:])
slice[0] = 0
fmt.Printf("array: %v\n", arr)
fmt.Printf("slice: %v\n", slice)
}
|
数组、切片使用
插入元素:
1
2
3
4
5
6
7
8
|
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 头部插入元素 [-1 0 1 2 3 4 5 6 7 8 9 10]
nums = append([]int{-1, 0}, nums...)
// 尾部插入元素 [1 2 3 4 5 6 7 8 9 10 99 100]
nums = append(nums, 99, 100)
fmt.Println(nums)
|
删除元素:
1
2
3
4
5
6
7
8
9
10
11
|
// 从头部删除 n 个元素
nums = nums[n:]
// 尾部删除 n 个元素
nums = nums[:len(nums)-n]
// 中间指定下标 i 位置开始删除 n 个元素
nums = append(nums[:i], nums[i+n:]...)
// 删除所有元素
nums = nums[:0]
|
拷贝:
1
2
3
4
5
|
func main() {
dest := make([]int, 0)
src := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(copy(dest, src))
}
|
clear:
clear 会将切片内所有的值置为零值.
1
2
3
4
|
func main() {
s := []int{1, 2, 3, 4}
clear(s)
}
|