day04 函式

染指未来發表於2024-07-02

普通函式

  • 定義 : func 函式名 {}
  • 執行函式 : 函式名()
  • 函式 型別
    • 無引數函式
    • 無返回值函式
    • 有1個或者多個 引數 函式
    • 有1個或者多個 返回值 函式
  • 引數的傳遞
    • 引用傳遞 切片
    • 值傳遞
  • 函式作用域
    • 函式內部的定義的變數,只能作用到函式內部
    • 全域性變數,函式內也可以使用
go code
package main

import "fmt"

func test1() {
	fmt.Println("執行test1")
}

func compareNum(num1 int, num2 int) int {
	if num1 < num2 {
		return num2
	} else {
		return num1
	}
}
func exchangeString(x string, y string) (string, string) {
	return y, x
}

func funcDefineReturn(x, y float64) (circumference float64, area float64) {
	// 不需要函式定義變數接收結果
	circumference = (x + y) * 2 // 周長
	area = x * y                // 面積
	// 函式定義好返回順序。return 可以不跟結果,直接按照函式定義順序返回結果
	return
}
func funcDefineReturnNotUse(x, y float64) (circumference float64, area float64) {
	circumference = (x + y) * 2 // 周長
	area = x * y                // 面積
	// 函式定義好返回順序。return 可以跟結果。將覆蓋函式定義時返回順序
	return area, circumference
}
func funcNotDefineReturnUse(x, y float64) (float64, float64) {
	// 需要自定義 函式內部變數接收結果
	circumference := (x + y) * 2 // 周長
	area := x * y                // 面積
	// 函式定義好返回順序。return 可以跟結果。將覆蓋函式定義時返回順序
	return circumference, area
}

func getSum(nums ...int) int {
	// ...any , ...any 表示可變引數。 可變引數必須放在最後面
	// nums 型別
	fmt.Printf("%T\n", nums) // []int 一維陣列
	sum := 0

	for i := 0; i < len(nums); i++ {
		sum += nums[i]
	}
	return sum
}
func main() {
	/*  go 中的函式 */
	// 定義 : func 函式名 {}
	// 執行函式  函式名()

	// 1. 函式執行
	test1()

	// 2. 函式 型別
	/*
		- 無引數函式
		- 無返回值函式
		- 有1個或者多個 引數 函式
		- 有1個或者多個 返回值 函式
	*/

	//  多個引數,且1個返回值. 返回值資料型別保持一致
	compareRes := compareNum(1, 2)
	fmt.Println("compareNum func result: ", compareRes)

	// 交換兩個string位置
	x := "hello"
	y := "word"
	fmt.Println("exchangeString func before: ", x, y)

	exchangeResX, exchangeResY := exchangeString(x, y)
	fmt.Println("exchangeString func result: ", exchangeResX, exchangeResY)

	// 匿名接收
	exchangeResX1, _ := exchangeString(x, y)
	fmt.Println("exchangeString anonymity func result: ", exchangeResX1)

	// return 結果
	/*
		- 1. 函式定義好返回順序。return 可以不跟結果,直接按照函式定義順序返回結果  funcDefineReturn
		- 2. 函式定義好返回順序。return 可以跟結果。將覆蓋函式定義時返回順序  funcDefineReturnNotUse
		- 3. 函式定義好返回順序。return 可以跟結果。將覆蓋函式定義時返回順序  funcNotDefineReturnUse
	*/
	fmt.Println("【邊長:1, 變長:2. 面積:2,周長:6】")
	circumference1, area1 := funcDefineReturn(1, 2)
	fmt.Println("circumference1:", circumference1, "area1", area1)
	circumference2, area2 := funcDefineReturnNotUse(1, 2)
	fmt.Println("circumference2:", circumference2, "area2", area2)
	circumference3, area3 := funcNotDefineReturnUse(1, 2)
	fmt.Println("circumference3:", circumference3, "area3", area3)

	// 可變引數: 一個函式的引數型別確定,引數的個數不確定。則使用可變引數 : ...any
	fmt.Println(getSum(1, 2, 3, 4, 5))

}

遞迴函式

  • 遞迴函式介紹
    • 函式自己呼叫自己,即:遞迴函式
    • 遞迴函式需要 終止條件。 否則形成死迴圈
    • 壓棧
go code
package main

import "fmt"

func recursionFBI(frequency int) int {
	// 遞迴終止條件
	if frequency <= 1 {
		return frequency
	}
	return recursionFBI(frequency-1) + recursionFBI(frequency-2)
}

func main() {

	// 遞迴函式,
	/*
		- 函式自己呼叫自己,即:遞迴函式
		- 遞迴函式需要 終止條件。 否則形成死迴圈
		- 壓棧
	*/

	// 練習題:斐波那契 結果:1,1,2,3,5,8,13,21,34,55
	/*
		斐波那契(前兩個相加等於新值)遞迴思路:
		迴圈 :1  結果 :1	n=1 r=1    終止條件(n-1)+ (n-2) = recursionFBI(frequency-1) + recursionFBI(frequency-2)
		迴圈 :2  結果 :1	n=1 r=1		1+0	(n-1)+ (n-2) = recursionFBI(frequency-1) + recursionFBI(frequency-2)
		迴圈 :3  結果 :2	n=2 r=2		2+0	(n-1)+ (n-2) = recursionFBI(frequency-1) + recursionFBI(frequency-2)
		迴圈 :4  結果 :3	n=3 r=3		3+0	(n-1)+ (n-2) = recursionFBI(frequency-1) + recursionFBI(frequency-2)
		迴圈 :5  結果 :5	n=1 r=1		4+1	(n-1)+ (n-2) = recursionFBI(frequency-1) + recursionFBI(frequency-2)
		迴圈 :6  結果 :8	n=1 r=1		5+3	(n-1)+ (n-2) = recursionFBI(frequency-1) + recursionFBI(frequency-2)
		迴圈 :7  結果 :13	n=1 r=1		7+6	(n-1)+ (n-2) = recursionFBI(frequency-1) + recursionFBI(frequency-2)
		......
	*/

	for i := 1; i <= 10; i++ {
		res := recursionFBI(i)
		fmt.Printf("迴圈次數:%d。斐波那契數:%d\n", i, res)

	}
}

defer 延時函式

  • defer 延時函式。 多個defer時,按照逆向順序執行。
  • defer 場景: 檔案流關閉,錯誤error,網路關閉等
go code
package main

import "fmt"

func test(s string) {
	fmt.Println(s)
}

func main() {
	/*
		- defer 延時函式。 多個defer時,按照逆向順序執行。
		- defer 場景: 檔案流關閉,錯誤error,網路關閉等
	*/

	//  defer 延時執行+逆序執行
	test("1")
	defer test("2")
	test("3")
	defer test("4")
	defer test("5")
	test("6")
	// 1 , 3, 6 , 5, 4 , 2

}

defer 函式中的呼叫

go code
package main

import "fmt"

func test2(n int) {
	fmt.Println("test2 函式中 defer n結果:", n)
}
func main() {
	// defer 在函式中延時執行
	n := 1
	fmt.Println("main n result start : ", n)
	defer test2(n) // n =1 已經傳入到函式中。類似於駐留機制
	n++
	fmt.Println("main n result end : ", n)

}

函式型別

  • func
go code
package main

import (
	"fmt"
	"reflect"
)

// 無參無返回值
func test3() {

}

// 有引數,有返回值
func test4(n1, n2 int) (int, int) {

	return 0, 0
}

// 有引數,有返回值. ...any
func test5(n1, n2 int, c ...string) (int, int, string) {

	return 0, 1, "2"

}
func main() {

	// 函式在go中。也屬於一種資料型別。  函式也可以賦值給變數,該變數定義時為函式原型別
	fmt.Printf("test3 函式型別: %T\n", test3) // test3 函式型別: func()
	fmt.Printf("test4 函式型別: %T\n", test4) // test4 函式型別: func(int, int) (int, int)
	fmt.Printf("test5 函式型別: %T\n", test5) //  test5 函式型別: func(int, int, ...string) (int, int, string)

	// 定義 變數接收函式
	var test6 func(int, int) (int, int)
	test6 = test4
	fmt.Printf("test6 函式型別: %T\n", test6)                             //  test6 函式型別: func(int, int, ...string) (int, int, string)
	fmt.Println("test6 函式記憶體地址: \n", reflect.ValueOf(test6).Pointer()) //  test6 函式記憶體地址:20792352
	fmt.Println("test4 函式記憶體地址: \n", reflect.ValueOf(test4).Pointer()) //  test4 函式記憶體地址:20792352

	f3, f4 := test6(1, 2)
	fmt.Println(f3, f4)

}

匿名函式

  • 匿名函式。沒有函式名的函式
go code
package main

import "fmt"

func main() {
	// 匿名函式。沒有函式名的函式
	anonymityFunc1 := func() {
		fmt.Println("123")
	}
	anonymityFunc1()

	// 匿名函式傳參,且有返回值.  傳遞引數必須要有結果。 形成:`閉包結構`. 類似於 前端 js 的閉包結構
	anonymityFunc3 := func(a1, b1 int) int {
		fmt.Println("匿名函式引數:a1", a1, "b1", b1)
		return a1 + b1
	}(1, 2)
	fmt.Println("匿名函式 傳參 的返回值:", anonymityFunc3)
}

回撥函式

  • 回撥函式就是一個被作為引數傳遞的函式

package main

import "fmt"

func main() {

	// 回撥函式。回撥函式就是一個被作為引數傳遞的函式

	// 1. 定義一個 sum 加法函式
	fmt.Println("sum:", sum(1, 2))
	sum1 := theReckonerFunc(1, 2, sum)
	fmt.Println("theReckonerFunc 加法:", sum1)
	fmt.Println()

	// 2. 定義一個 變數 sub 減法函式
	sub := func(a, b int) int {
		return a - b
	}
	sub1 := theReckonerFunc(1, 2, sub)
	fmt.Println("theReckonerFunc 減法:", sub1)
	fmt.Println()

	// 3. 定義 一個 匿名函式 乘法函式
	multiplication1 := theReckonerFunc(2, 3, func(a, b int) int {
		return a * b
	})
	fmt.Println("theReckonerFunc 乘法:", multiplication1)
	fmt.Println()
	// 4. 定義 一個 匿名函式 除法函式
	punishment1 := theReckonerFunc(6, 3, func(a, b int) int {
		if b == 0 {
			return 0
		}
		return a / b
	})
	fmt.Println("theReckonerFunc 處法:", punishment1)

}

// 計算器函式
func theReckonerFunc(a, b int, fc func(a, b int) int) int {
	fmt.Println("計算器函式計算方法:", fc)
	return fc(a, b)
}

// sum 函式
func sum(a, b int) int {
	return a + b
}

go函式 閉包

  • 一個外層函式中,有內層函式,該內層函式中,會操作外層函式的區域性變數並且該外層函式的返回值就是這個內層函式。
    • 在閉包結構中:區域性變數的生命週期就會發生改變,
    • 正常的區域性變數會隨著函式的呼叫而建立,隨著函式的結束而銷燬
    • 但是閉包結構中的外層函式的區域性變數並不會隨著外層函式的結束而銷燬,因為內層函式還在繼續使用.
package main

import "fmt"

func main() {

	cf1 := closureFunc()
	fmt.Printf("呼叫【closureFunc】函式。變數 cf1 記憶體地址:%p\n", &cf1)
	fmt.Printf("呼叫【closureFunc】函式。變數 cf1 值:%d\n\n", cf1)

	//cf3 := closureFunc()
	//fmt.Printf("呼叫【closureFunc】函式。變數 cf3 記憶體地址:%p\n", &cf3)
	//fmt.Printf("呼叫【closureFunc】函式。變數 cf3 值:%d\n\n", cf3)

	// cf1,cf2,cf3  指向同一個匿名函式記憶體地址

	cf1Res := cf1()
	fmt.Printf("呼叫【cf1】函式。結果 cf1 記憶體地址:%p\n", &cf1Res)
	fmt.Printf("呼叫【cf1】函式。結果 cf1 值:%d\n\n", cf1Res)
	cf1Resclosure := cf1()
	fmt.Printf("呼叫【cf1 cf1Resclosure】函式。結果 cf1 cf1Resclosure 記憶體地址:%p\n", &cf1Resclosure)
	fmt.Printf("呼叫【cf1 cf1Resclosure】函式。結果 cf1 cf1Resclosure 值:%d\n\n", cf1Resclosure)
	fmt.Println("'-----------------'")
	cf2 := closureFunc()
	fmt.Printf("呼叫【closureFunc】函式。變數 cf2 記憶體地址:%p\n", &cf2)
	fmt.Printf("呼叫【closureFunc】函式。變數 cf2 值:%d\n\n", cf2)

	cf2Res := cf2()
	fmt.Printf("呼叫【cf2】函式。結果 cf2 記憶體地址:%p\n", &cf2Res)
	fmt.Printf("呼叫【cf2】函式。結果 cf2 值:%d\n\n", cf2Res)

	//cf3Res := cf3()
	//
	//fmt.Printf("呼叫【cf3】函式。結果 cf3 記憶體地址:%p\n", &cf3Res)
	//fmt.Printf("呼叫【cf3】函式。結果 cf3 值:%d\n\n", cf3Res)

}

func closureFunc() func() int {
	i := 0
	fmt.Printf("外層函式 內 i 變數 記憶體地址:%p\n", &i)
	fmt.Printf("外層函式 內 i 變數 :%d\n\n", i)

	retFunc := func() int {

		fmt.Printf("呼叫 【前】函式。全域性變數 i 記憶體地址:%p\n", &i)
		fmt.Printf("呼叫 【前】函式。全域性變數 i 值:%d\n\n", i)
		i++
		fmt.Printf("呼叫 【後】函式。全域性變數 i 記憶體地址:%p\n", &i)
		fmt.Printf("呼叫 【後】函式。全域性變數 i 值:%d\n\n", i)
		return i
	}
	fmt.Printf("內層函式 retFunc 記憶體地址:%p\n", &retFunc)

	return retFunc // 返回函式

}

相關文章