[Golang] 函數, 匿名函數,閉包,可變參數,遞迴, 延遲執行

函數

輸入的參數可多個, 返回也可多個

func 函數名(參數)(返回值){
    函數體
}

範例:

package main

import "fmt"

func main() {

    fmt.Println(sum(2, 3)) //5
    x, y := getXYValue()
    fmt.Printf("x:%d y:%d", x, y) //x:1 y:2

    var f func() //指定function類型
    f = process  //把process這個func指定給f
    f()          // 調用f等於調用process
}

func sum(x, y int) int {
    return x + y
}

func getXYValue() (x, y int) {
    x = 1
    y = 2
    return x, y
}

func process() {
    fmt.Println("use process function")
}

匿名函數

package main

import "fmt"

func main() {
    //匿名函數

    f := func(name string) {
        fmt.Println("hello,", name)
    }
    f("bocky") //hello, bocky
    fmt.Println("===")

    iterator([]int{1, 2, 3, 4, 5, 6}, func(value int) { //函數沒有名稱
        fmt.Println(value)
    })
}

func iterator(arr []int, ff func(int)) { // 這裡的函數是有名稱ff
    for _, value := range arr {
        ff(value)
    }
}

閉包

閉包 = 函數+引用環境

範例:

package main

import "fmt"

func main() {
    //str := "Bocky" // IDE會出現str declared but not used
    f := func() {
        str := "Abby"
        fmt.Println(str) //Abby
    }
    f()

    //  閉包擁有記憶性
    fmt.Println("======")
    add1 := add(1)
    fmt.Println(add1())       //2
    fmt.Println(add1())       //3
    fmt.Printf("%p\n", &add1) //0xc000006030

    fmt.Println("======")
    add2 := add(200)
    fmt.Println(add2())       //201
    fmt.Println(add2())       //202
    fmt.Printf("%p\n", &add2) //0xc000006038

    fmt.Println("======")
    bocky := user("bocky")
    name, hp := bocky()
    fmt.Println(name, hp) //bocky 1000

    fmt.Println("======")
    amy := user("amy")
    name2, hp2 := amy()
    fmt.Println(name2, hp2) //amy 1000
}

func add(v1 int) func() int {
    return func() int {
        v1++
        return v1
    }
}

func user(name string) func() (string, int) {
    hp := 1000
    return func() (string, int) {
        return name, hp
    }
}

可變參數

在實際開發中,總有一些函數的參數個數是在編碼過程中無法確定的,
當有狀況是需要實現類似的接口時,就會用到”可變參數”了。

package main

import (
    "bytes"
    "fmt"
)

func main() {
    //可變參數
    funx1(1)
    funx1(1, 2, 3, 5)

    funx2(11)                   //11 int
    funx2("1234")               //1234 string
    funx2(1.23)                 //1.23 default
    funx2(func() () { return }) //0x96ca00 default

    fmt.Println("=======")
    fmt.Println(funx3("hello "))
    fmt.Println(funx3("hello ", "I'm "))           //hello I'm
    fmt.Println(funx3("hello ", "I'm ", "Bocky!")) //hello I'm Bocky!



    fmt.Println("=======")
    Tprint("A","B","C")
}

func funx1(args ...int) { //不確定會傳多少個int的時候可以使用...但一定要是int類型
    for _, arg := range args {
        fmt.Println(arg)
    }
}

func funx2(args ...interface{}) { //任一類型的可變參數
    for _, arg := range args {
        switch arg.(type) {
        case int:
            fmt.Println(arg, "int")
        case string:
            fmt.Println(arg, "string")
        case float32:
            fmt.Println(arg, "float32")
        default:
            fmt.Println(arg, "default")
        }
    }
}

func funx3(strs ...string) string {
    var b bytes.Buffer
    for _, s := range strs { // 依序遍歷strs內的string
        b.WriteString(s)
    }
    return b.String()
}

//下方Tprint會call funx4來執行print的動作
func Tprint(params ...interface{}) {
    funx4(params)
}
func funx4(params ...interface{}) {
    for _, value := range params {
        fmt.Println(value)
    }
}

計算函數時間

想要獲取計算某個任務從開始到結束的運行時間,我們可以使用time包中的Slice函數,用法:

func Since (t Time) Duration

t是時間值。
此方法是time.Now().Sub(t)的快捷方式

package main

import (
    "fmt"
    "time"
)

func main() {
    //func Since(t Time)Duration
    //time.Now().sub(t
    testTime()
}

func testTime() {

    start := time.Now()
    sum := 0
    for i := 0; i < 1000000000; i++ {
        sum++
    }
    duration := time.Since(start)
    fmt.Println("function執行時間:", duration)
}

遞迴

費波那契數列

1,1,2,3,5,8,13 ,...
package main

import "fmt"

func main() {
    //遞迴

    result := 0
    for i := 1; i <= 10; i++ {
        result = fibonacci(i)
        fmt.Printf("fibonacci(%2d) -> %3d\n", i, result)
    }
}

func fibonacci(n int) (rtn int) {
    if n <= 2 {
        rtn = 1
    } else {
        rtn = fibonacci(n-1) + fibonacci(n-2)
    }
    return
}

defer 延遲執行

  • 用於資源的釋放,會在函數返回之前進行調用,簡單來說就是宣告 function “結束前”的動作。
  • 先進後出
  • 會保留當下狀態

簡單的範例:

package main

import (
    "fmt"
)


func main() {
    fmt.Println("defer start")
    defer fmt.Println(1)
    defer fmt.Println(2)
    defer fmt.Println(3)
    fmt.Println("defer stop")
}

結果:

defer start
defer stop
3
2
1
package main

import (
    "fmt"
)

func main() {
    num := 1
    x := addOne(num)

    fmt.Printf("Result is %d\n",x)
}


func closeProcess() {
    fmt.Println("close process")
}
func addOne(x int) int {
    fmt.Println("Start process")
    defer closeProcess() // function結束前返回
    if x > 2 {
        fmt.Println("x > 2")
        return x * 20
    } else {
        fmt.Println("x <=2")
        return x + 1
    }
}

結果:

Start process
x <=2
close process
Result is 2

發佈留言

內容索引