乐趣区

关于go:上篇Go函数的骚包玩法有哪些

1. 用 type 关键字能够定义函数类型,函数类型变量能够作为函数的参数或返回值。

package main

import "fmt"

func add(a, b int) int {return a + b}

func sub(a, b int) int {return a - b}

type Task func(int, int) int

func exec(t Task, a, b int) int {return t(a, b)
}

func main() {a := exec(add, 10, 20)
    fmt.Println(a)

    b := exec(sub, 100, 95)
    fmt.Println(b)
}

解析:type Task func(int, int) int,这句是说,应用 type 关键字定义 1 个类型为 func 的 Task,这个 func 有 2 个 int 形参、1 个 int 返回值。再看 exec 这个函数,它有 3 个形参,形参 t 的类型是刚定义的函数类型 Task,另外两个你懂的,我就不说了。

2. 匿名函数的玩法是真的骚,看看骚在哪里

  • 栗子 1:匿名函数能够间接赋给变量

    func main() {var aaa = func(a, b int) int {return a + b}
      ret := aaa(89, 78)
      fmt.Println(ret)
    }

    输入:

    167
  • 栗子 2:匿名函数作为函数入参

    这个例子感觉跟方才应用 type 关键字定义函数类型的例子有点雷同的赶脚,认真一看,如同也只是在应用的形式上是一样,定义函数的套路又是不同的。

    func work(f func(int, int) int, a, b int) int {return f(a, b)
    }
    
    func add(a, b int) int {return a + b}
    
    func main() {a := work(add, 100, 200)
      fmt.Println(a)
    }

    输入:

    300

    解析:形参 f 的类型就是匿名函数,持续看 func(int, int) int,这个匿名函数接管两个 int 形参,返回值也是 int 类型。另外两个形参 a 和 b,也是 int,想必你懂了,我就不废话了。

  • 栗子 3:匿名函数作为函数出参

    匿名函数作为函数出参(作为函数返回值),经一直调测,有 3 种骚包玩法,爽死了。

  1. 骚包玩法 1

    // 先来个简略的
    func work() func() int {return func() int {return 10 + 20}
    }
    
    func main() {f := work()
     ret := f()
     fmt.Println(ret)
    }

    输入:

    30
  2. 骚包玩法 2

    // 再革新下
    func work(a, b int) func() int {return func() int {return a + b}
    }
    
    func main() {f := work(500, 20)
     ret := f()
     fmt.Println(ret)
    }

    输入:

    520
  3. 骚包玩法 3

    // 再次革新
    func work() func(int, int) int {return func(a, b int) int {return a + b}
    }
    
    func main() {f := work()
     ret := f(600, 50)
     fmt.Println(ret)
    }

    输入:

    650
  4. 对 3 种骚包玩法的简略解析:

    再这里就解析一下第 3 种玩法,能搞懂这个玩法,后面 2 个玩法,你就天然懂了。work 函数没有入参,然而有出参(也能够说是返回值),出参是匿名函数 func(int, int) int,这个定义在返回值里的匿名函数有 2 个 int 类型的形参(入参)和 1 个 int 类型的返回值。再看看函数体外部,没干很简单活儿,而是间接 return 了匿名函数,函数体里的这个匿名函数是和定义在返回值里的类型保持一致的,也是接管了 2 个 int 的形参 a 和 b,返回值也是 int,啥也没干,就做了个相加。好郁闷!不晓得你看懂了没?再看看是如何应用 work 函数的,关键点就在这里,调用 work()赋给了变量 f,这时候,f 它就是一个函数了,再调用 f(600, 50),想必你曾经晓得了为啥要传入 2 个 int 值,这下搞定!不晓得把你绕晕没,这玩法的确很骚。

3. 匿名函数和提早调用

提早调用的规定是:依照 先进后出 的程序,也就是说函数返回前是会被执行的,而且是依照先进后出的程序。如何起到提早的成果,是须要注册的,可通过 defer 关键字进行注册。那么什么场景下须要用到提早调用呢?比方常见的场景:当一个函数被行将执行完后,也就是实现工作的最初一刻,须要回收和开释某些资源。

提早调用的机制能够配合匿名函数来应用,这样就能够让匿名函数被间接调用,只能说是真的骚。

先看个小栗子:

package main

import "fmt"

func work() bool {fmt.Println("函数开始工作...")
    defer func() {fmt.Println("回收相干资源工作开始!")
    }()
    defer func() {fmt.Println("清理工作开始!")
    }()
    fmt.Println("函数正在工作...")
    fmt.Println("函数工作结束...")
    return true
}
func main() {status := work()
    fmt.Println(status)
}

输入:

函数开始工作...
函数正在工作...
函数工作结束...
清理工作开始!回收相干资源工作开始!true

在下面的栗子中,定义了个 work 函数,先看看输入的后果,感触下。在 work 函数中,注册了两个提早调用,work 函数从开始 -> 正在 -> 结束,完结后才执行 defer 注册的匿名函数,这里要着重留神提早调用规定:先进后出,也就是先注册后执行。“回收相干资源工作”是先注册的,他的执行程序排在了“清理工作”的前面。感触到了吗?

最初阐明一下:defer 关键字让匿名函数实现了可间接调用,那么应用 defer 注册提早调用时要留神,defer 关键字的前面肯定是要函数或办法的调用,不能间接写语句哦。

本文转载于(喜爱的盆友关注咱们):https://mp.weixin.qq.com/s/Dt…

退出移动版