普通函數定義
√ golang函數基本組成:關鍵字func、函數名、參數列表、返回值、函數體和返回語句。
• 語法如下
func 函數名(參數列表) (返回值列表) { // 函數體 }
• 示例如下
package main import "fmt" import "errors" func Add(a int, b int) (ret int, err error) { if a < 0 || b < 0 { // 假定只支持兩個非負數字的加法 err = errors.New("Should be non-negative numbers!") return } return a + b, nil } func main() { fmt.Println(Add(-1, 1)) fmt.Println(Add(10, 1)) }
• 注意事項
▪ golang函數支持多返回值,返回時沒有被明確賦值的返回值將被設置為默認值。
▪ golang函數返回值可以命名,但不是強制規則,給返回值命名可以讓讓代碼更清晰,可讀性更強,同時也可以用於文檔。
▪ golang函數定義中左花括號的位置被強制規范,如果左花括號放置不規范,golang編譯器報告編譯錯誤:syntax error: unexpected semicolon or newline before {。
▪ golang函數定義中如果參數列表中若干個相鄰參數的類型相同,則可以在參數列表中省略前面的變量類型聲明。
func Add(a, b int) (ret int, err error) { // 函數體 }
▪ golang函數定義中如果返回值列表中若干個相鄰返回值的類型相同,則可以在返回值列表中省略前面的變量類型聲明。
func Add(a, b int) (ret, err int) { // 函數體 }
▪ golang函數定義中如果返回值只有一個,那么返回值列表可以簡略表示。
func Add(a, b int) int { // 函數體 }
固定類型的不定參數函數定義
• 語法如下
func 函數名(args ...Type) (返回值列表) {
// 函數體
}
√ 形如args ...Type的用法只能作為函數的參數類型,並且必須是最后一個參數。
√ 形如args ...Type的用法是一個語法糖(syntactic sugar),即對語言功能沒有影響,但可以增加程序的可讀性。
√ 形如args ...Type的用法從內部實現上說,其本質上是一個數組切片,即[]type,因此可以用for循環來獲得每個傳入的參數。
• 示例如下
package main import "fmt" func myfunc(prefix string, args ...int) { fmt.Print(prefix, " : ") for _, arg := range args { fmt.Print(arg, " ") } fmt.Println() } func main() { myfunc("data1", 1, 2, 3, 4) myfunc("data2", 4, 3, 2, 1, 0) }
• 不定參數函數互相調用
▶ 原樣傳遞
▪ 語法如下
func myfunc1(args ...Type) { // 函數體 } func myfunc2(args ...Type) { ... myfunc1(args...) ... }
▪ 示例如下
package main import "fmt" func myfunc1(args ...int) { fmt.Println("myfunc1() invoked") for _, arg := range args { fmt.Print(arg, " ") } fmt.Println() } func myfunc2(args ...int) { fmt.Println("myfunc2() invoked") myfunc1(args...) } func main() { myfunc2(1, 2, 3, 4) }
▶ 片段傳遞
▪ 語法如下
func myfunc1(args ...Type) { // 函數體 } func myfunc2(args ...Type) { ... myfunc1(args[m:n]...) ... }
▪ 示例如下
package main import "fmt" func myfunc1(args ...int) { fmt.Println("myfunc1() invoked") for _, arg := range args { fmt.Print(arg, " ") } fmt.Println() } func myfunc2(args ...int) { fmt.Println("myfunc2() invoked") myfunc1(args[2:3]...) } func main() { myfunc2(1, 2, 3, 4) }
任意類型的不定參數函數定義
• 語法如下
func 函數名(args ...interface{}) (返回值列表) { // 函數體 }
√ 形如args ...interface{}的用法只能作為函數的參數類型,並且必須是最后一個參數。
• 示例如下
package main import "fmt" func MyPrintf(info string, args ...interface{}) { fmt.Println(info) for _, arg := range args { switch arg.(type) { case int: fmt.Println(arg, "is an int value.") case string: fmt.Println(arg, "is a string value.") case int64: fmt.Println(arg, "is an int64 value.") default: fmt.Println(arg, "is an unknown type.") } } } func main() { var v1 int = 1 var v2 int64 = 234 var v3 string = "hello" var v4 float32 = 1.234 MyPrintf("MyPrintf", v1, v2, v3, v4) }
匿名函數與閉包
• 匿名函數
√ 匿名函數是指不需要定義函數名的一種函數實現方式,函數可以像普通變量一樣被傳遞或使用。
▶ 匿名函數賦值給變量
▪ 語法如下
f := func(參數列表) (返回值列表) { // 函數體 }
▪ 示例如下
package main import "fmt" func main() { f := func(x, y int) int { return x + y } fmt.Println("Result =", f(1, 2)) }
▶ 匿名函數直接調用
▪ 語法如下
√ 匿名函數定義的花括號后直接跟參數列表表示函數調用。
func(參數列表) (返回值列表) { // 函數體 } (參數列表)
▪ 示例如下
package main import "fmt" func main() { fmt.Println("Result =", func(x, y int) int { return x + y }(1, 2)) }
• 閉包
▶ 閉包概念
√ 閉包是可以包含自由變量(未綁定到特定對象)的代碼塊。這些自由變量不在該代碼塊內或任何全局上下文中定義,而是在定義代碼塊的環境中定義。要執行的代碼塊為自由變量提供綁定的計算環境,即作用域。
√ 自由變量包含在代碼塊中,這些自由變量以及其引用的對象將不被釋放。閉包的實現確保只要閉包還被使用,那么被閉包引用的變量會一直存在。
√ golang的匿名函數就是一個閉包,閉包函數可以存儲到變量中作為參數傳遞給其他函數,最重要的是能夠被函數動態創建和返回。
√ 自由變量的值將被隔離,在閉包外不可修改,只有內部匿名函數才能訪問,而無法通過其他途徑訪問,因此確保了變量的安全性。
▶ 閉包使用
▪ 語法如下
c := func() func(參數類型列表) 返回值類型列表 { // 自由變量定義
... return func(參數列表) 返回值列表 { // 函數定義 } }()
▪ 示例如下
package main import ( "fmt" ) func main() { result := 0 // 閉包定義 c := func() func(int) int { i := 0 return func(j int) int { i += 10 fmt.Printf("i = %d, j = %d\n", i, j) return i + j } }() result = c(10) fmt.Printf("i + j= %d\n", result) result = c(20) fmt.Printf("i + j= %d\n", result) result = c(30) fmt.Printf("i + j= %d\n", result) }
main函數
√ main函數是golang可執行程序的執行起點。
√ main函數不能帶有參數,命令行傳入的參數在os.Args變量中保存。
package main import ( "fmt" "os" ) func main() { for i, v := range os.Args { fmt.Printf("os.Args[%d] = %s\n", i, v) } }
