返回值及參數說明閉包
func A(a int, b string) (int, string, int) { //第一個小括號當中是你的參數列表,第二個小括號是你的返回值列表 }
func A(a, b, c int) (int, string, int) { //若是abc都是int型的話,能夠按照這種方法進行簡寫,一樣的方法也適用於返回值當中 }
func A() (a, b, c int) { //1:若是這樣寫的話就必需要命名返回值 //命名返回值和不命名返回值得區別 }
func A() (int, int, int) { // //命名返回值和不命名返回值得區別 a, b, c := 1,2,3 return a,b,c //若是此時沒有命名返回值的時候,那麼在返回值得時候就必須寫上return a,b,c //固然爲了代碼的可讀性,這裏咱們規定必須return 的時候加上返回值名 }
不定長變參函數
package main import "fmt" func main() { A(1,2,3,4,5,6,7) } func A(a ...int) { // 這裏採用的是不定長變參,不定長變參必須是參數的最後一個參數,後面不能再跟 b string這樣的參數 fmt.Println(a) }
package main import "fmt" func main() { s1:= []int{1,2,3,4} a,b :=1,2 A(a,b) fmt.Println(a,b) B(s1) fmt.Println(s1) } func A(a ...int) { //這裏傳進來的其實是一個slice,引用類型 a[0] = 3 a[1] = 4 //儘管咱們在函數A當中接收到的是一個slice,可是它獲得的是一個值拷貝 //和直接傳遞一個slice的區別看函數B fmt.Println(a) } func B(s []int) { //這裏並非傳遞一個指針進去,而是對這個slice的內存地址進行了一個拷貝 //這裏還能夠看到像int型、string型進行常規的參數傳進去的話,只是進行了個值拷貝,slice傳進去雖然也是拷貝,可是它是內存地址的拷貝 s[0] = 4 s[1] = 5 s[2] = 6 s[3] = 7 fmt.Println(s) //在這裏 咱們看到咱們在函數B當中的修改,實際上影響到了咱們main函數當中的變量s1 //若是直接傳遞一個slice,它的修改就會影響到這個slice的自己 } PS:值類型和引用類型進行函數傳參拷貝是不同的,一個是拷貝值,一個是拷貝地址
package main import ( "fmt" ) func main() { a := 1 A(&a) //這裏取出a的地址 fmt.Println(a) } func A(a *int) { //傳遞的是指針類型 *a = 2 //在操做的時候須要去它的值進行操做,這個時候函數A就能夠改變原始a的值 fmt.Println(*a) }
函數類型的使用指針
package main import ( "fmt" ) func main() { a := A a() //這個時候是將A的函數類型賦值給a,在go語言當中一切皆是類型啊 } func A() { fmt.Println("Func A") }
匿名函數的使用code
package main import ( "fmt" ) func main() { a := func() { //此時這個代碼塊就是一個匿名函數,這個函數自己沒有名稱,咱們將她賦值給a,而後調用 fmt.Println("Func A") } a() //依然能夠打印func A }
GO語言當中的閉包內存
package main import ( "fmt" ) func main() { f := closure(10) res1 := f(1) fmt.Println(res1) res2 := f(2) fmt.Println(res2) } func closure(x int) func(int) int { fmt.Printf("%p \n", &x) return func(y int) int { fmt.Printf("%p \n", &x) return x + y } } //這裏能夠看出3次打印x的地址都是同樣的
若是函數體內某個變量做爲defer時匿名函數的參數,則在定義defer時即已經得到了拷貝,不然則是引用某個變量的地址資源
Panic能夠在任何地方引起,但recover只有在defer調用的函數中有效原型
package main import ( "fmt" ) func main() { fmt.Println("A") defer fmt.Println("B") defer fmt.Println("C") } //PS:打印的結果就是A C B
package main import ( "fmt" ) func main() { for i := 0; i < 3; i++ { //defer fmt.Println(i) defer func() { fmt.Println(i) }() //調用這個函數 } } //剛纔直接打印的時候,是做爲一個參數傳遞進去,運行到defer的時候是將這個i的值進行了一個拷貝,因此打印的是 2 1 0 //這種狀況下i一直是一個地址的引用,i一直引用的是局部變量的i,在退出這個循環體的時候 i已經變成了3,在main函數return的時候,開始執行defer語句,defer語句的時候i已經變成了3
異常機制string
package main import ( "fmt" ) func main() { A() B() C() } func A() { fmt.Println("Func A") } func B() { defer func() { if err := recover(); err != nil { fmt.Println("Recover in B") } }() panic("Panic in B") } func C() { fmt.Println("Func C") }
package main import ( "fmt" ) func main() { var fs = [4]func(){} for i := 0; i < 4; i++ { defer fmt.Println("defer i=", i) //這個i是傳遞進來的參數,因此是值得拷貝 defer func() { fmt.Println("defer_closure i=", i) //這裏的i是引用外部的i,因此循環結束後,i變成了4 }() fs[i] = func() { fmt.Println("closure i = ", i) //這裏也是引用外部的i,因此循環結束後i變成了4 } } for _, f := range fs { f() } }