內容

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知識

相關文章