首頁 > 軟體

Go語言func匿名函數閉包範例詳解

2022-06-13 14:03:54

前言

今天繼續為大家更新Go語言學習記錄的文章。

函數是任何一門程式語言最重要的組成部分之一。函數簡單理解是一段程式碼的封裝:把一段邏輯抽象出來封裝到一個函數中,給他取個名字,每次需要的時候呼叫這個函數即可。使用函數能夠讓程式碼更清晰,更簡潔。

定義

下面的程式碼段介紹了go語言中函數定義的各種情況,以及延遲函數的使用。

package main
import "fmt"
// 函數的定義
func f1(x int, y int) (ret int) {
   return x + y
}
// 無返回值的函數
func f2(x int, y int) {
   fmt.Println(x + y)
}
// 沒有引數也沒有返回值的
func f3() {
   fmt.Println("1111")
}
// 沒有引數 有返回值的
func f4() int {
   return 4
}
// 返回值可以命名也可以不命名
// 命名的返回值就相當於在函數中宣告一個變數
func f5(x int, y int) (ret int) {
   ret = x + y  //注意:因為已經在返回值中宣告了ret,所以這裡用= 而不是:= ,避免重複宣告問題
   return //因為已經在函數體中宣告了ret,所以在return的時候不需要重複宣告
}
// 多個返回值
func f6() (int, int) {
   return 1, 2
}
// 多個引數簡寫的方式
// 當引數的型別一致時,可以將連續的相同引數 前面引數的型別省略 比如:
func f7(x, y, z int, a, b string, c, d bool) int {
   return x + y + z
}
// 可變長引數
// 可變長引數必須放在函數引數的最後
func f8(x string, y ...int) {
   fmt.Println(x)
   fmt.Println(y)
}
// defer 延遲執行
func deferDemo() {
   defer fmt.Println("111") //最先defer的語句最後執行
   defer fmt.Println("222")
   fmt.Println("333")
}
// go語言中函數沒有預設引數的概念
func main() {
   r := f5(1, 2)
   fmt.Println(r)
   m, n := f6()
   fmt.Println(m, n)
   r7 := f7(1, 2, 3, "1", "1", true, false)
   fmt.Println(r7)
   f8("hah") //可變長度 不填也可以
   f8("hah", 1, 2, 3, 4)
   //延遲函數測試
   deferDemo()
}

函數也可以作為函數的引數

舉個栗子:

package main
import "fmt"
// 函數也可以作為函數引數的型別
func f3(x func() int) {
   ret := x()
   fmt.Printf("f3列印ret的值:%vn", ret) //2
   fmt.Printf("f3列印ret的型別:%Tn", ret) //int
}
func main() {
   a := f2
   fmt.Printf("a的型別:%Tn", a)
   f3(a)
}

列印結果:

函數作為函數的返回值

package main
import "fmt"
func f2() int {
   return 2
}
func ff(x, y int) int {
   return x + y
}
// 函數不僅可以作為引數,還可以作為返回值
func f5(x func() int) func(int, int) int {
   return ff
}
func main() {
   f7 := f5(f2)
   fmt.Printf("f7的值:%vn",f7) //f7返回的是一個函數
   fmt.Printf("f7的型別:%Tn", f7)
}

列印結果:

小結:

  • 我們列印f7的值是一個記憶體地址
  • f7的型別和我們預期的一致,返回了函數型別,就是我們定義的ff()函數

匿名函數

匿名函數就是沒有名字的函數。匿名函數多用於實現回撥函數和閉包。

在Go語言中函數內部不能再像之前那樣定義函數了,只能定義匿名函數。

匿名函數的定義格式如下:

func(引數)(返回值){
    函數體
}

匿名函數因為沒有函數名,所以沒辦法像普通函數那樣呼叫,所以匿名函數需要儲存到某個變數或者作為立即執行函數:

func main() {
	// 將匿名函數儲存到變數
	add := func(x, y int) {
		fmt.Println(x + y)
	}
	add(10, 20) // 通過變數呼叫匿名函數
	//自執行函數:匿名函數定義完加()直接執行
	func(x, y int) {
		fmt.Println(x + y)
	}(10, 20)
}

小結:自執行函數就是在匿名函數後面追加(),表示不需要外部呼叫,直接執行。

閉包

閉包是一個函數,這個函數包含了他外部作用域的一個變數

舉個栗子

package main
import "fmt"
func adder(x int) func(int) int {
   return func(y int) int {
      x += y
      return x
   }
}
func main() {
   f1 := adder(1)
   ret := f1(2)
   fmt.Println(ret)
}

列印結果:

小結: 上面的栗子就是一個典型的閉包結構:匿名函數內部包含了他外部的變數x。

閉包=函數+參照環境

總結

這篇文章我們詳細介紹了Go語言中函數的定義、也介紹了匿名函數和閉包的知識點,更多關於Go語言func匿名函數閉包的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com