Go 語言函式

隱姓埋名4869發表於2022-03-25

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

  

 

相關文章