使用函数

函数就是将一段输入数据转换为输出数据的公用代码块闭包

函数示例函数

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")
}

结果图