Go 語言函式
1. 概述
函式是基本的程式碼塊,用於執行一個任務
Go 語言最少有一個 main() 函式
你可以通過函式來劃分不同功能,邏輯上每個函式執行的是指定的任務
函式宣告告訴了編譯器函式的名稱,返回型別,和引數
Go 語言標準庫提供了多種可動用的內建的函式。
例如,len()函式可以接受不同型別引數並返回該型別的長度。如果我們傳入的是字串則返回字串的長度,如果傳入的是陣列,則返回陣列中包含的元素個數。
2. 函式的定義
Go 語言函式定義格式如下:
func 函式名 (引數列表) (返回值列表)
無引數返回值
func test() { }
傳參有返回值
func test(a int,b int) int { return n }
傳參有多個返回值
func result(a int,b int)(int,int) { return a+b,a*b }
- 示例: 定義max()函式傳入兩個整形引數 num1 和 num2,並返回這兩個引數的最大值
/* 函式返回兩個數的最大值 */ func max(num1, num2 int) int { /* 宣告區域性變數 */ var result int if num1 > num2 { result = num1 } else { result = num2 } return result }
3. 函式呼叫
- 當建立函式時,你定義了函式需要做什麼,通過呼叫該函式來執行指定任務,呼叫函式,向函式傳遞引數,並返回值
函式的呼叫
package main import "fmt" func main() { var ( a int = 100 b int = 200 ) var result int //函式呼叫,注意返回值和接受值型別必須一致 result = max(a, b) fmt.Println("最大值為:", result) } /* 函式返回兩個數的最大值 */ func max(num1, num2 int) int { /* 宣告區域性變數 */ var result int if num1 > num2 { result = num1 } else { result = num2 } return result } //輸出結果如下 最大值為: 200
函式返回多個值
package main import "fmt" func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("hello", "world") fmt.Println(a, b) } //輸出結果如下 world hello
package main import "fmt" func main() { var ( a, b = multi_value(3, 5) ) fmt.Println("和:", a, "\n積:", b) } func multi_value(num1, num2 int) (int, int) { result1 := num1 + num2 result2 := num1 * num2 //返回兩數和,兩數乘積 return result1, result2 } //輸出結果如下 和: 8 積: 15
4. 函式引數
- 函式如果使用引數,該變數可稱為函式的
形參
- 形參就像定義在函式體內的區域性變數
- 呼叫函式,可以通過兩種方式來傳遞引數
預設情況下,Go 語言使用的是值傳遞,即在呼叫過程中不會影響到實際引數
傳遞型別 | 描述 |
---|---|
值傳遞 | 值傳遞是指在呼叫函式時將實際引數複製一份傳遞到函式中,這樣在函式中如果對引數進行修改,將不會影響到實際引數 |
引用傳遞 |
引用傳遞是指在呼叫函式時將實際引數的 |
值型別
package main import "fmt" func main() { var ( num1 = 10 num2 = 20 ) fmt.Println("交換前\n") fmt.Printf("num1: %v\n", num1) fmt.Printf("num2: %v\n", num2) swap(num1, num2) fmt.Println("\n交換後\n") fmt.Printf("num1: %v\n", num1) fmt.Printf("num2: %v\n", num2) } //兩數交換 func swap(a, b int) { a, b = b, a } //輸出結果如下 交換前 num1: 10 num2: 20 交換後 num1: 10 num2: 20
總結:
可以看到,實際的值並沒有交換,只是把實際引數給複製了一份傳遞到了函式中去,並不會影響原本的實際引數
引用型別
package main import "fmt" func main() { var ( num1 = 11 num2 = 22 ) fmt.Println("交換前") fmt.Printf("num1: %v, num2: %v\n", num1, num2) fmt.Println("-----------------") swap(&num1, &num2) fmt.Println("交換後") fmt.Printf("num1: %v, num2: %v\n", num1, num2) } //引用型別交換 func swap(a, b *int) { *a, *b = *b, *a } //輸出結果如下 交換前 num1: 11, num2: 22 ----------------- 交換後 num1: 22, num2: 11
5. 函式作為實參
-
可以很靈活的建立函式,並作為另一個函式的實參
-
示例:
使用math
數學包
package main import ( "fmt" "math" ) func main() { //函式變數 result := func(x float64) float64 { return math.Sqrt(x) } fmt.Println(result(9)) fmt.Println("-10的絕對值:", math.Abs(-10)) fmt.Println("5.2向下取整:", math.Ceil(5.2)) fmt.Println("5.8向下取整:", math.Floor(5.8)) fmt.Println("11除3的餘數:", math.Mod(11, 3)) fmt.Println("取整數,取小數") fmt.Println(math.Modf(5.26)) fmt.Println("3的2次方", math.Pow(3, 2)) fmt.Println("10的4次方", math.Pow10(4)) fmt.Println("8的開平方", math.Sqrt(8)) fmt.Println("8的開立方", math.Cbrt(8)) fmt.Println("圓周率", math.Pi) } //輸出結果如下 3 -10的絕對值: 10 5.2向下取整: 6 5.8向下取整: 5 11除3的餘數: 2 取整數,取小數 5 0.2599999999999998 3的2次方 9 10的4次方 10000 8的開平方 2.8284271247461903 8的開立方 2 圓周率 3.141592653589793
6. 回撥函式
回撥函式是一個被作為引數傳遞的函式,可以大大提升程式設計的效率。
函式執行流程描述
① 首先在main函式中呼叫了test1()函式,這時候test1會順著去載入裡面的語句 1、2,直到語句2載入完後,載入回撥函式test2,test2會執行函式體內的語句 1、2,3;
② 當test2函式體中語句執行完成,回撥函式的生命週期將結束,如果有返回值將返回,沒有則結束;
③ 當回撥函式執行完以後,將繼續執行test1函式中的語句 3,4,執行完以後test1函式的生命週期也將結束
④ test1函式結束以後就會返回main主函式
package main import "fmt" //宣告函式型別 type cback func(int) int func main() { //對回撥函式進行隱匿,能起到保護作用,並且提高程式的執行效率 test_cback(1, callback) } //測試函式,用來呼叫回撥函式 func test_cback(x int, f cback) { fmt.Println("test_back函式:語句1") f(x) fmt.Println("test_back函式:語句2") } //回撥函式 func callback(a int) int { fmt.Println("回撥函式callback:", a) return a } //執行結果如下 test_back函式:語句1 回撥函式callback: 1 test_back函式:語句2
7. 匿名函式
- 匿名函式就是沒有函式名的函式,匿名函式多用於實現回撥函式和閉包
- 匿名函式是一個"內聯"語句或表示式
- 匿名函式的優越性在於可以直接使用函式內的變數,不必申明
- 匿名函式的定義格式如下:
func(引數)(返回值){ 函式體 }
匿名函式的執行方式如下
- ① 把匿名函式賦值給變數
package main import "fmt" func main() { sayHello := func() { fmt.Println("匿名函式") } sayHello() } //執行結果如下 匿名函式
- ② 立即執行函式
package main import "fmt" func main() { func() { fmt.Println("匿名函式") }() //匿名函式定義完成加上()可以直接進行執行 } //執行結果如下 匿名函式
8. 閉包
- 閉包可以理解為
定義在一個函式內部的函式
,本質上閉包是將函式內部和外部連線起來的橋樑,或者說是函式和其引用環境的組合體 - 閉包指的是一個函式和與其相關的引用環境組合而成的實體。簡單來說,
閉包=函式+引用環境
閉包示例 ①
package main import "fmt" //定義一個函式,他的返回值是一個函式 //把函式作為返回值 func a() func() { name := "world" return func() { fmt.Println("hello", name) //先在函式內找name變數,找不到就上函式體外層去找 } } func main() { //閉包 = 函式+外出變數的引用 r := a() //r就是一個閉包 r() //相當於執行了a函式的匿名函式 } //執行結果 hello world
示例 ②
package main import ( "fmt" "strings" ) //使用閉包做檔案字尾名檢測 func makeSuffixFunc(suffix string) func(string) string { return func(name string) string { if !strings.HasSuffix(name, suffix) {//判斷字串字尾的格式 return name + suffix } return name } } func main() { jpgFunc := makeSuffixFunc(".jpg") txtFunc := makeSuffixFunc(".txt") fmt.Println(jpgFunc("test")) fmt.Println(txtFunc("test")) } //執行結果如下 test.jpg test.txt
示例 ③
package main import "fmt" func calc(base int) (func(int) int, func(int) int) { add := func(i int) int { base += i return base } sub := func(i int) int { base -= i return base } return add, sub } func main() { x, y := calc(100) ret1 := x(200)//呼叫x的時候傳入值為200;base = 100 + 200 fmt.Printf("ret1: %v\n", ret1) ret2 := y(200)//base = 300 - 200 fmt.Printf("ret2: %v\n", ret2) } //輸出結果如下 ret1: 300 ret2: 100
- 示例 ④
//回撥函式是把函式作為傳遞引數,而閉包則是把函式作為一個返回值 package main import "fmt" func close_package() func() int { i := 0 return func() int { i += 1 return i } } func main() { //定義函式 使用閉包做+1操作 nextNumber := close_package() fmt.Println("使用nextNumber做自增") fmt.Println(nextNumber()) fmt.Println(nextNumber()) fmt.Println(nextNumber()) fmt.Println("使用nextNumber1做自增") nextNumber1 := close_package() fmt.Println(nextNumber1()) fmt.Println(nextNumber1()) fmt.Println(nextNumber1()) } //執行結果如下 使用nextNumber做自增 1 2 3 使用nextNumber1做自增 1 2 3