函數就是將一段輸入數據轉換爲輸出數據的公用代碼塊閉包
函數示例函數
package main import "fmt" func slice_sum(arr []int) int { sum := 0 for _, elem := range arr { sum += elem } return sum } func main() { var arr1 = []int{1, 3, 2, 3, 2} var arr2 = []int{3, 2, 3, 1, 6, 4, 8, 9} fmt.Println(slice_sum(arr1)) fmt.Println(slice_sum(arr2)) }
一、命名返回值,即爲返回值預先定義一個名稱,最後直接一個return,就能夠將預約義的返回值所有返回ui
從新定義上面的求和函數,示例代碼以下spa
func slice_sum(arr []int) (sum int) { sum = 0 for _, elem := range arr { sum += elem } return }
二、函數多返回值,即同時返回多個值code
package main import "fmt" func slice_sum(arr []int) (int, float64) { sum := 0 //注意是float64類型 avg := 0.0 for _, elem := range arr { sum += elem } avg = float64(sum) / float64(len(arr)) return sum, avg } func main() { var arr = []int{3, 2, 3, 1, 6, 4, 8, 9} fmt.Println(slice_sum(arr)) }
也能夠用預命名返回值名稱方式編寫函數代碼blog
func slice_sum(arr []int) (sum int, avg float64) { sum = 0 //注意是float64類型 avg = 0.0 for _, elem := range arr { sum += elem } avg = float64(sum) / float64(len(arr)) return }
三、變長參數;變長參數列表內參數類型都是相同的、可變長參數只能是函數的最後一個參數遞歸
package main import "fmt" func sum(base int, arr ...int) int { sum := base for _, val := range arr { sum += val } return sum } func main() { fmt.Println(sum(100, 2, 3, 4)) }
變長參數的函數傳入切片,以下,注意切片後面的三個點ci
func main() { var arr = []int{2, 3, 4} fmt.Println(sum(100, arr...)) }
四、閉包函數:簡單理解就是在函數內,定義一個返回函數的變量,能夠經過該變量執行其定義的函數,而且在變量函數內可使用或改變外部函數的變量值資源
package main import "fmt" func main() { var base = 300 sum := func(arr ...int) int { total_sum := base for _, val := range arr { total_sum += val } return total_sum } arr := []int{1, 2, 3, 4} fmt.Println(sum(arr...)) }
閉包示例:生成偶數序列,輸出 0,2,4string
package main import "fmt" func createEvenGenerator() func() uint { i := uint(0) return func() (retVal uint) { retVal = i i += 2 return } } func main() { nextEven := createEvenGenerator() fmt.Println(nextEven()) fmt.Println(nextEven()) fmt.Println(nextEven()) }
五、遞歸函數,函數內重複調用本身,直到遇到出口,如階乘函數,出口就是當x=0,示例以下
package main import "fmt" func factorial(x uint) uint { if x == 0 { return 1 } return x * factorial(x-1) } func main() { fmt.Println(factorial(5)) }
斐波拉切數列,出口是n=1和n=2
package main import "fmt" func fibonacci(n int) int { var retVal = 0 if n == 1 { retVal = 1 } else if n == 2 { retVal = 2 } else { retVal = fibonacci(n-2) + fibonacci(n-1) } return retVal } func main() { fmt.Println(fibonacci(5)) }
六、異常處理
1)defer標註,不論在函數中的什麼位置,都是最後執行,即便中間有異常,也會最後執行defer標識的代碼,以下面例子,雖然second函數在first函數前面,可是最後執行
package main import "fmt" func first() { fmt.Println("first func run") } func second() { fmt.Println("second func run") } func main() { defer second() first() }
defer用於資源釋放的案例
package main import ( "bufio" "fmt" "os" "strings" ) func main() { fname := "D:\\test.txt" f, err := os.Open(fname) defer f.Close() if err != nil { os.Exit(1) } bReader := bufio.NewReader(f) for { line, ok := bReader.ReadString('\n') if ok != nil { break } fmt.Println(strings.Trim(line, "\r\n")) } }
2)、panic觸發異常,在defer中使用recover函數接收異常信息,recover只能在defer中才有效,由於異常拋出後,下面的代碼不會執行,defer會在最後執行
package main import ( "fmt" ) func main() { defer func() { msg := recover() fmt.Println(msg) }() fmt.Println("I am walking and singing...") panic("It starts to rain cats and dogs") }
結果圖