go語言 函數和包
一、函數
在Go語言中,函數是執行特定任務的自包含代碼塊。
1.函數的定義
函數通過func
關鍵字定義,格式如下:
func 函數名(形參 形參類型, 形參 形參類型) 返回值類型 {函數體return 返回值 }
2.基礎函數類型
- 無參數無返回值
- 單個參數,無返回值
- 多個相同類型參數,無返回值
- 多個不同類型參數,無返回值
- 多個參數,一個返回值
- 多個參數,多個返回值
package mainimport "fmt"func main() {demo01()//demo02("d") // 類型不匹配demo02(2)demo03(1, 2)demo04(1, "A")var res = demo05(1, 2)fmt.Println("a+b:", res)var res1, res2 = demo06(1, 1)fmt.Println(res1, res2) }// 無參數無返回值 func demo01() {fmt.Println("hello world") }// 單個參數,無返回值 func demo02(a int) {fmt.Println("a:", a) }// 多個相同類型參數,無返回值 func demo03(a, b int) {fmt.Println("a+b:", a+b) }// 多個不同類型參數,無返回值 func demo04(a int, b string) {fmt.Println("a:", a)fmt.Println("b:", b) }// 多個參數,一個返回值 func demo05(a, b int) int {return a + b }// 多個參數,多個返回值 func demo06(a, b int) (int, bool) {if a+b > 3 {return a + b, true} else {return a * b, false} }
3.特殊函數類型
- 匿名函數:
test06
展示了如何在Go中定義匿名函數,即沒有函數名的函數。 - 函數作為一等公民:
f
變量可以存儲函數,test11
返回一個函數作為其結果。 - 命名返回值:
test10
展示了如何使用命名返回值,這有助于提高代碼的可讀性。 - 閉包:
test12
是一個閉包示例,它捕獲并使用外部作用域的變量。 - 函數作為參數:
test14
接受一個函數作為參數,并在函數體內調用它。 - 類型重命名:
MyFunc
是func(string) (int, int)
類型的別名。
package mainimport "fmt"func main() {demo01()// 函數作為一等公民var demo02 = func(a, b int) int {return a + b}var res = demo02(15, 16)fmt.Println(res)var res1, res2 = demo03(16, 17)fmt.Println(res1, res2)// 閉包var ff = demo04(15)ff()// 函數作為參數var f1 = func(a int) {fmt.Println(a)}demo05(15, f1)// 類型重命名type StringProcessor func(string) stringprocessor := StringProcessor(func(input string) string {return "Processed: " + input})result := processor("Input")fmt.Println(result)}// 匿名函數 func demo01() {fmt.Println("demo01--start")// 定義匿名函數并立即執行func() {fmt.Println("demo01--inner")}()fmt.Println("demo01--end") }// 命名返回值 func demo03(a, b int) (sum int, flag bool) {sum = a + bflag = true//return sum, flag // 可以指定return // 也可以不在指定 }// 閉包 func demo04(x int) func() {x = 666f := func() {fmt.Println("我是內部函數", x)}return f }// 函數作為參數 func demo05(a int, f func(i int)) {f(a) }
4.裝飾器函數
-
Go語言雖然沒有像一些其他語言(例如Python)那樣的裝飾器語法,但是可以通過閉包來實現類似的功能。
-
裝飾器通常用于在不修改原始函數代碼的情況下增加函數的功能。
-
示例
package mainimport ("fmt""time" )// 普通函數 func sayHello(name string) string {time.Sleep(time.Second) // 延遲1秒return "Hello " + name }// 自定義裝飾器,計時功能 func timeTrack(fn func(string) string) func(string) string {return func(name string) string {startTime := time.Now() // 記錄開始時間result := fn(name) // 調用原始函數elapsedTime := time.Since(startTime) // 計算經過時間fmt.Printf("耗時: %s \n", elapsedTime)return result} } func main() {// 使用裝飾器增強原始函數enhanceSayHello := timeTrack(sayHello)helloMessage := enhanceSayHello("world")fmt.Println(helloMessage) }
二、包
在Go語言中,包(package)是組織源代碼的基本單位,它有助于代碼的可重用性和可讀性
1.包規則
- 導出規則:如果一個函數、變量或類型的名稱以大寫字母開頭,它就是導出的(exported),這意味著它可以在包外部被訪問和使用。如果以小寫字母開頭,則它在包外部是不可見的。
- 包名一致性:在同一個文件夾下的所有Go源文件應該屬于同一個包,并且包名通常建議與文件夾名相同。這是為了保持代碼的清晰和易于理解。
- 包內部可見性:在同一個包內的所有源文件共享相同的包級作用域,這意味著這些文件中的所有變量、函數和類型都像是在同一個文件中一樣可見。
- 使用包:要使用其他包中的導出成員,需要導入對應的包,并通過包名來引用它們。
- 導入包:使用
import
關鍵字來導入包。導入時,通常使用包的全路徑名,例如import "demo/common"
。 - 導入并重命名包:如果包名沖突或者為了方便引用,可以在導入時為包指定一個新的名稱,例如
import cv1 "demo/common/v1"
。 - 一次導入多個包:可以通過一對花括號來一次導入多個包,這樣可以保持代碼的整潔。
2.示例
-
目錄結構
-
demo/ ├── common/ │ ├── v1/ # v1 是 common 包的一個子目錄,表示版本1 │ │ └── demo01.go # demo01.go 是 common 包 v1 版本的實現文件 │ ├── demo02.go # demo02.go 是 common 包的一部分,不在任何子目錄中 │ └── demo01.go # 這是 common 包的另一個實現文件,可能與 v1 版本不同 └── main.go # main.go 是 main 包的入口文件,通常包含 main 函數 └── go.mod # go.mod 是 Go 模塊的配置文件,記錄模塊的依賴關系
-
-
文件內容
-
// main.go package main// 導入標準庫中的fmt包 import "fmt"// 一次導入多個包 import ("demo/common"cv1 "demo/common/v1" // // 導入包并重命名 )func main() {// 使用fmt包的Println函數fmt.Println("Hello, world!")res1 := common.Add(1, 2)fmt.Println(res1)res2 := cv1.Mul(4, 5) // 使用重命名的包fmt.Println(res2) }
-
// common/demo01.gopackage common func Add(a, b int) int {return a + b }
-
// common/demo02.gopackage common func Addd(a, b int) int {return Add(a, b) + b }
-
// common/v1/demo01.gopackage v1 func Mul(a, b int) int {return a * b }
-