package main

/*
defer

类似其它语言中的析构函数,在函数体执行结束后
按照调用顺序的相反顺序逐个执行,先进后出,
即使函数发生严重错误也会执行,资源清理文件关闭,
支持匿名函数的调用
常用于资源清理、文件关闭、解锁以及记录时间等操作
通过与匿名函数配合可在return之后修改函数计算结果
如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer
时即已经获得了拷贝,如果不是参数则是引用某个变量的地址

Go 没有异常机制,但有 panic/recover 模式来处理错误
Panic 可以在任何地方引发,但recover只有在defer调用的函数中有效

*/

import (
    "fmt"
)

func main1() {
    fmt.Println("a")
    defer fmt.Println("b")
    defer fmt.Println("c") //acb,相反顺序逐个执行,先进后出,
}

func main2() {
    fmt.Println("a")
    defer fmt.Println("b")
    defer fmt.Println("c")

    for i := 0; i < 3; i++ {
        defer fmt.Println(i)
    } //    a 2 1 0 c b
}

func main3() {
    for i := 0; i < 3; i++ {
        defer func() {
            fmt.Println(i)
        }() // 3 3 3,for循环结束的时候i=3,而当main函数结束的时候开始执行defer,此时i一直是3(存在闭包)
    }
}

//go语言没有异常机制,也就是没有try catch,defer就类似于finally,
//go语言的异常机制是panic/recover 模式来处理错误,Panic 可以在任何地方引发,但recover只有在defer调用的函数中有效
//函数发生错误的时候,函数已经不执行了,只能靠defer来执行一些恢复操作,所以recover只能放在defer调用的函数中才是有意义的。

func main4() {
    A()
    B()
    C() //AAAAAAA,   panic:BBBBBBBB
}

func A() {
    fmt.Println("AAAAAAA")
}

func B() {
    panic("BBBBBBBB") //B已经panic了,C函数不执行,程序终止执行了,
}

func C() {
    fmt.Println("VCCCCCC")
}

func main() {
    A1()
    B1()
    C1()
    //AAAAAAA   recover in B     VCCCCCC
    //通过defer将程序从panic状态恢复回来,恢复到正常执行,
}

func A1() {
    fmt.Println("AAAAAAA")
}

func B1() {
    //恢复panic,要写在panic之前,因为如果执行了panic了后面的代码不再执行了,
    //那么defer就注册不了recover函数了,(defer函数是在函数执行完之后执行的,相当于只是注册了里面的一些函数)
    defer func() {
        if err := recover(); err != nil { //err为函数中出现的错误,err不为空,引发了panic,说明revcover有效,恢复panic,
            fmt.Println("recover in B")
        }
    }()
    panic("BBBBBBBB") //B已经panic了,C函数不执行,程序终止执行了,
}

func C1() {
    fmt.Println("VCCCCCC")
}

slice和map是引用类型, 

匿名函数不能作为顶级函数,只能够放在函数里面,

panic和recover类似于其他语言的try catch,用于异常的返回和错误的处理  。出现了错误panic,要从错误中恢复过来,  程序进入panic之后函数不再执行(类似于发生了错误跑出了异常),要想在panic之后仍然能够执行recover函数就需要用到defer,defer是不管任何情况都会执行用defer定义的函数,将recover放在defer中,并且defer要放在可能发生panic的语句之前,