1. 程式人生 > >Golang panic,defer,return 的返回

Golang panic,defer,return 的返回

Golang返回過程-return,defer,panic

首先有以下幾個原則:

  1.  函式返回return是函式的返回標誌,並不是真正的返回,不代表執行結束
  2. 一個函式最多隻會panic一次
  3. defer按先進後出的形式執行,defer在return之後執行

return 和 defer

一個有返回值的函式,可以有2中表示
  func sum1(x,y int)int{
       s := x+y
       return s
    }

    func sum2(x,y int)(s int){
        s = x+y
        return
    }

    func main(){
        s1 := sum1(1,2)
        s2 := sum2(1,2)
        print(s1)   // 3
        print(s2)   // 3
    }
這sum1和sum2結果是一樣的,但是組合上defer,會有不一樣結果:
    
  func sum3(x,y int)int{
        s := x+y
        defer func(){
            s += 2
        }()
        return s
    }

    func sum4(x,y int)(s int){
        s = x+y
        defer func(){
            s += 2
        }()
        return
    }
    
    func main(){
        s3 := sum3(1,2)
        s4 := sum4(1,2)
        println(s3)   // 3
        println(s4)   // 5
    }
s3=3,s4=5,對於這個過程的理解是:
  1. 函式在開始執行的時候,先初始化了它的返回值,如果位宣告,隨機一個temps,如果聲明瞭,即s
  2. 在執行到return(返回標誌)的時候賦值。
    • sum3函式先在執行到return時候,將tempS賦值為s,即3。由於s和tempS3是不同的變數,defer中的s+2就與tempS3無關。 
    •  sum4函式由於聲明瞭返回變數s,return時候,如果是 `return x+y`,其實將`x+y`複製給s,如果直接return,可以理解為跳過了複製操作。
在return之後的defer,s與sum3所謂的tempS3其實是一個,所以defer的操作是有效的。有些部落格用作用域來解釋這一現象,看起來比較抽象。

 defer 和 panic

func main() {
    	var a int
    	// fn1
    	defer func() {
    		a = 3
    		if err := recover(); err != nil {
    			a = 4
    			fmt.Println("++++")
    			f := err.(func() string)
    			fmt.Println(err, f(), reflect.TypeOf(err).Kind().String())
    		} else {
    			fmt.Println("fatal")
    		}
    	}()
        // fn2
    	defer func() {
    		a = 2
    		if r := recover(); r != nil {  // 這裡的recover()去掉感受一下效果
    			panic(r)
    		}
    		panic(func() string {
    			return "defer panic"
    		})
    	}()
    	a = 1
    	panic("panic1")  // 這裡的panic去掉感受一下效果
    	// panic("panic2")
    }
defer有棧deferStack,首先按順序執行,fn1,進入deferStack,並標記有recover() ,fn2,進入deferStack,並標記有recover() , 然後panic,panic("panic2")是執行不到的。在deferStack中棧頂發現recover(),執行他,繼續panic,panic會沿著deferStack向下遞交,在fn1中又發現recover(),執行之。但是現在發現,deferStack已經執行到棧底了,程式認為執行完畢,就不會執行fn2的panic了。