汇总
- make
- new
- iota
- defer
- panic
- recover
- for…range…
- select
make和new
定义
- make 的作用是初始化内置的数据结构,比如切片、哈希表和 Channel;
- new 的作用是根据传入的类型分配一片内存空间并返回指向这片内存空间的指针;
区别
- make 只能用于创建 map、slice、channel;
- make 会进行初始化,new 不会初始化,new只是申请一段内存空间,并返回指向这片内存的指针
代码
package main
import "fmt"
func main() {
slice := make([]int, 10, 11)
tempMap := make(map[int]int, 10)
tempChannel := make(chan int, 10)
fmt.Println(slice)
fmt.Println(tempMap)
fmt.Println(tempChannel)
}
----------------------运行结果-------------------------
[0 0 0 0 0 0 0 0 0 0]
map[]
0x140000be000
iota
定义
iota 是一个常量生成器,用于简化定义递增枚举值的过程。它通常用于 const 声明块中,每当 const 声明块中的每一行新声明时,iota 的值会递增。
代码
package main
import "fmt"
const (
a = iota
b
c
)
func main() {
fmt.Println("a = ", a)
fmt.Println("b = ", b)
fmt.Println("c = ", c)
}
----------------------运行结果-------------------------
a = 0
b = 1
c = 2
defer
定义
defer 关键字用于延迟执行一个函数,直到包含 defer 的函数执行完毕后才会运行。defer 通常用于资源清理、文件关闭、解锁互斥锁等场景,确保在函数返回之前,一些必要的清理工作一定会被执行,即使函数中间发生了错误或者提前返回。
代码
单个defer
package main
import "fmt"
func main() {
defer say()
fmt.Println("你好")
}
func say() {
fmt.Println("hello world")
}
----------------------运行结果-------------------------
你好
hello world
多个defer
后进先出原则
package main
import "fmt"
func main() {
defer fmt.Println("我是第一个defer")
defer fmt.Println("我是第二个defer")
defer fmt.Println("我是第三个defer")
fmt.Println("你好")
}
----------------------运行结果-------------------------
你好
我是第三个defer
我是第二个defer
我是第一个defer
参数被前置定义
定义defer函数的时候,参数已经被前置定义了,不过此时会去区分是指针还是副本,如果是副本,则后续的修改都不影响defer,否则会影响defer。
package main
import "fmt"
type Student struct {
Name string
Age int
}
func main() {
fmt.Println(change())
fmt.Printf("%+v\n", changeStudent())
fmt.Println(changeI())
}
func change() int {
i := 1
defer func() {
i = 8
}()
return i
}
func changeStudent() *Student {
student := &Student{
Name: "zhangsan",
Age: 18,
}
defer func() {
student.Age = 80
}()
return student
}
func changeI() (res int) {
res = 1
defer func() {
res++
}()
return res
}
----------------------运行结果-------------------------
1
&{Name:zhangsan Age:80}
2
panic 和 recover
定义
- panic 能够改变程序的控制流,调用 panic 后会立刻停止执行当前函数的剩余代码,并在当前 Goroutine 中递归执行调用方的 defer;
- recover 可以中止 panic 造成的程序崩溃。它是一个只能在 defer 中发挥作用的函数,在其他作用域中调用不会发挥作用;
代码
panic会导致整个进程终止,后续逻辑不再运行
package main
import "fmt"
// panic 的case
func main() {
fmt.Println("start")
panic("there is a panic")
fmt.Println("end")
}
----------------------运行结果-------------------------
start
panic: there is a panic
goroutine 1 [running]:
main.main()
/Users/bytedance/GolandProjects/awesomeProject/main.go:7 +0x6c
使用recover捕获panic,使得程序能够正常运行,但是panic仍然会导致当前goruntine的停止
package main
import "fmt"
// case1
func main() {
fmt.Println("start")
defer func() {
if err := recover(); err != nil {
fmt.Println("recover from panic")
}
}()
panic("there is a panic")
fmt.Println("end")
}
----------------------运行结果-------------------------
start
recover from panic
package main
import "fmt"
package main
import "fmt"
package main
import (
"fmt"
"time"
)
// case2
func main() {
fmt.Println("start")
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recover")
}
}()
fmt.Println("go start")
panic("go there is a panic")
fmt.Println("go end")
}()
time.Sleep(1 * time.Second)
fmt.Println("end")
}
----------------------运行结果-------------------------
start
go start
recover
end
for range
定义
通常配合起来联合使用,用作迭代字符串、数组、切片、映射、通道的访问。
代码
package main
import "fmt"
func main() {
arr := [5]int{1, 2, 3, 4, 5}
slice := []int{1, 2, 3, 4, 5}
tempMap := make(map[int]int)
tempMap[1] = 1
tempMap[2] = 2
tempMap[3] = 3
channel := make(chan int)
s := "1234"
go func() {
defer close(channel)
channel <- 1
channel <- 2
channel <- 3
}()
for index, elemet := range arr {
fmt.Printf("arr[%d] = %d ", index, elemet)
}
fmt.Println()
for index, elemet := range slice {
fmt.Printf("slice[%d] = %d ", index, elemet)
}
fmt.Println()
for key, value := range tempMap {
fmt.Printf("tempMap[%d] = %d ", key, value)
}
fmt.Println()
for v := range channel {
fmt.Printf("channel = %d ", v)
}
fmt.Println()
for _, i := range s {
fmt.Printf("char = %d ", i)
}
}
----------------------运行结果-------------------------
arr[0] = 1 arr[1] = 2 arr[2] = 3 arr[3] = 4 arr[4] = 5
slice[0] = 1 slice[1] = 2 slice[2] = 3 slice[3] = 4 slice[4] = 5
tempMap[3] = 3 tempMap[1] = 1 tempMap[2] = 2
channel = 1 channel = 2 channel = 3
char = 49 char = 50 char = 51 char = 52
select
定义
select 关键字用于处理多个通道(channels)操作的同时选择。它类似于 switch 语句,但 select 是专门用于通道操作的,它可以在多个通道上等待发送或接收操作,并且一旦某个通道操作完成,select 会执行对应的代码块。也可以做一些超时控制。
代码
select相当于switch,只不过仅操作通道
package main
import "time"
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
go func() {
for i := 0; i < 10; i++ {
ch1 <- i
}
}()
go func() {
time.Sleep(8 * time.Second)
ch1 <- 2
}()
go func() {
time.Sleep(9 * time.Second)
ch1 <- 3
}()
select {
case <-ch1:
println("ch1")
case <-ch2:
println("ch2")
case <-ch3:
println("ch3")
case <-time.After(4 * time.Second):
println("timeout")
default:
println("default")
}
}
----------------------运行结果-------------------------
ch1