defer

多个 defer

栈方式执行,最后 defer 的操作最先执行。

return 与 defer

  1. 为 return 指定返回的实数值或地址。
  2. 执行 defer 指令。
  3. 执行 RET 命令,最终返回值。
 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
// 不带命名返回值
func test() int {
  	i := 0
  	defer func() {
      	i++
      	fmt.Println("ans2: ", i)
    }()
  	defer func() {
      	i++
      	fmt.Println("ans1: ", i)
    }()
  	return i
}
// ans1: 1
// ans2: 2
// return 0
/*****************************************************/
// 带命名返回值
func test() (i int) {
  	defer func() {
      	i++
      	fmt.Println("ans2: ", i)
    }()
  	defer func() {
      	i++
      	fmt.Println("ans1: ", i)
    }()
  	return i
}
// ans1: 1
// ans2: 2
// return 2

make 与 new

new 非配内存,并不初始化,默认设为 0 值,可以被直接使用。返回指向这段地址的指针。

make 只能够初始化 Slice, map,channel 三种数据结构,因为这三个的底层结构体中的部分字段(len, cap 等)需要被初始化。


空结构体

struct{}不占据任何内存空间

一般有三个用途:

  1. 实现set集合
  2. 和channel配合使用,不具备任何意义,但除用作goroutine之间通知
  3. 实现一个不带字段,仅包含方法的结构体

进程、线程、协程

进程:操作系统分配资源的最小单位,拥有独立的寄存器、栈、内存空间等上下文资源。

线程:程序运行的最小单位,同一进程可能拥有多个线程,每个占有虚拟内存空间,共享进程的资源。

协程:更小的单位,有调度器实现。

  • 大小:协程约为 2K,可以动态扩容;线程约 2M。
  • 切换:协程完全在用户态实现;线程需要用户态和内核态的切换。
  • 调度:协程由 runtime 调度器完成;线程由操作系统调度。