Go 語言函數
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

