go闭坑指南

内容

1 切片与数组

2 defer

3 make与new

4 方法与函数

1 切片和数组

  1. 数组和结构体都是值变量,即:如果把一个数组变量和结构体变量赋值给另外的变量,是拷贝了一份值,两者的修改互不影响;

2 . go通过切片生成另外一个切片时,两个切片共享同一个底层数组,对其中一个修改元素时,两个都会改变;

例如:
    a=[]int{1,2,3}
    b:=a[:]
    b[0] = 2
    printLn(a[0]) —》输出:2
  1. 特别注意初始化切片时,如果指定了切片的长度,go会用nil来填充这个切片, 如果是基本类型则用基本类型零值填充,此后对切片通过append操作时,会在后面进行填充;所以在初始化一个切片并且指定了容量时,要注意长度初始化为0;
a := []int{1,2,3}
b := make([]int, 0, len(a)) //Yes
B := make([]int, len(a), len(a)) //No

B1 := make([]int, 0) //Yes
b1 := make([]int, 4) //No

2 defer

1.对于defer,当代码运行到defer语句时,defer后要运行的函数的入参此时已经确定了(即:defer函数的入参函数此时就被执行了,而不是到了调用是才被执行),defer下面的语句对该参数做的修改对于函数无效;;

2.如果同一个函数中有多个defer,被推迟的函数按照先进后出的顺序执行(压栈出栈),即:最后一个defer会被第一个执行;

func main(){
   b()
}

func un(s string) {
   fmt.Println("leaving:", s)
}


func trace(s string) string {
   fmt.Println("enter:", s)
   return s
}

func b() {
   defer un(trace("b"))
   fmt.Println("in:", "b")
   a()
}


func a() {
   defer un(trace("a"))
   fmt.Println("in:", "a")
}

打印:
    enter: b
    in: b
    enter: a
    in: a
    leaving: a
    leaving: b

3.defer 原理

  • 后调用的 defer 函数会先执行:
    • 后调用的 defer 函数会被追加到 Goroutine _defer 链表的最前面;
    • 运行 runtime._defer 时是从前到后依次执行;
  • 函数的参数会被预先计算;
    • 调用 runtime.deferproc 函数创建新的延迟调用时就会立刻拷贝函数的参数,函数的参数不会等到真正执行时计算;

3 make与new

make和new的区别:make只能用于slice map和channel,返回的是该类型初始化后的引用;new(T)返回的是指向该类型的指针。

type File struct{
   name string
}

&File{} 《=》 new(File)
    
```
make只用于映射、切片和管道,并且不返回指针,如果要得到指针请使用new
```
var p *[]int = new([]int) // 得到指针
var v []int = make([]int, 0, 100)

var p *[]int = new([]int)
*p = make([]int, 100)

4 方法和函数

1、函数中如果入参是值参数,那么该函数只能接收值入参;如果方法中的接收器是值接收器,那么该方法可以接收值接收器和指针接收器,即:可以通过该类型接收器的值变量和指针变量调用方法;

2、函数中如果入参是指针参数,那么只能接收指针参数;如果方法中申明的接收器是指针接收器,那么该方法可以接收值接收器和指针接收器;

引用:

  1. 《go语言实现与设计》 https://draveness.me/golang/
  2. 《effective go》 https://www.kancloud.cn/kancloud/effective/72214

欢迎关注我们的微信公众号,每天学习Go知识