上篇: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种骚包玩法,爽死了。

// 先来个简单的
func work() func() int {
    return func() int {
        return 10 + 20
    }
}

func main() {
    f := work()
    ret := f()
    fmt.Println(ret)
}

输出:

30
// 再改造下
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
// 再次改造
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

再这里就解析一下第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关键字的后面一定是要函数或方法的调用,不能直接写语句哦。

Original: https://www.cnblogs.com/ttropsstack/p/16732798.html
Author: 不背锅运维
Title: 上篇:Go函数的骚包玩法有哪些

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/582287/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • JavaScript编程基础(一)

    目的: 熟练掌握JavaScript的语言基础,包括数据类型、常量和变量、运算符和表达式、基本语句和函数。 理解JavaScript如何动态产生HTML代码,以及控制CSS。 要求…

    Linux 2023年6月13日
    0108
  • Postman环境变量的使用

    前言 请注意,Postman新版有ui上的改动,本文使用的Postman 版本8.4.0 for Mac, ui有调整,但是功能无改变。 Postman是一款接口调测的软件,服务端…

    Linux 2023年6月14日
    0122
  • 青春浙江微信平台如何退出?如何重新登录?微信如何清除浏览器缓存,如何清除浏览器cookies?

    青春浙江不能退出重新登录,有同学可能寻找解决方法,给大家贴出来:bug 解决办法:1. debugmm.qq.com/?forcex5=true 打开调试2. http://deb…

    Linux 2023年6月14日
    0141
  • shell内置命令和外部命令的区别

    shell内置命令和外部命令的区别 内部命令实际上是shell程序的一部分,其中包含的是一些比较简单的linux系统命令,这些命令由shell程序识别并在shell程序内部完成运行…

    Linux 2023年6月7日
    097
  • k8s/kubeadm 生产环境高可用集群部署

    kubeadm 生产环境集群部署 基本环境配置 kubeadm 安装方式自 1.14 版本以后,安装方法几乎没有任何变化,此文档可以尝试安装最新的 k8s 集群, centos 采…

    Linux 2023年6月14日
    0113
  • Spring事务(四)-事务隔离级别

    Spring @Transactional注解isolation属性 @Transactional注解通过isolation属性设置事务隔离级别。如下: @Transactiona…

    Linux 2023年6月6日
    087
  • 数字证书编码ASN.1

    任务详情 参考附件中图书p223 中13.2的实验指导,完成DER编码 序列号=1174(0x0496),证书签发者 DN=”CN=Virtual CA,C=CN&#8…

    Linux 2023年6月8日
    075
  • 域控制器所需的DNS SRV记录没有在DNS中注册的解决方法

    搭建完AD和DNS之后,发现在DNS的正向查找区域没有SRV记录,并且客户端无法加入到AD中,如下 解决方法 删除正向查找区域下的目录 然后选择”正向查找区域&#822…

    Linux 2023年6月14日
    0134
  • 四年测试的面试题分享

    其实想说为什么每次面试都要先来点自我介绍,说来说去简历上都有,我曾想过不能快速进入面试阶段嘛 我的专业技能: 基本上这些专业技能是在工作上用过或者自己摸索过,实战经验比较少,下面是…

    Linux 2023年6月8日
    0110
  • 每周一个linux命令(tree)

    安装tree命令 yum install tree -y 显示当前目录下的一级目录结构 tree -L 1 目录信息说明 bin: 系统常用命令所在目录 boot: 系统启动相关的…

    Linux 2023年6月8日
    0114
  • 需求分析到软件设计复习

    什么是需求分析? 需求分析就是需求分析师对用户期望的软件行为进行表述。 谁来表述 -> 需求分析师 谁有期望-> 用户 期望什么?-> 期望的软件行为 怎样表述?…

    Linux 2023年6月8日
    0129
  • C 中的字符数组

    在C语言中没有专门的字符串变量,字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。通常用一个 字符数组来存…

    Linux 2023年6月13日
    0113
  • windows系统如何查看端口被占用、杀进程

    查看系统当前所有的端口使用情况 命令:netstat -ano 查看特定端口是否被占用: netstat -ano |findstr “端口号” 查看到对应…

    Linux 2023年6月13日
    0121
  • Supervisor进程管理

    Supervisor 介绍 Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。它…

    Linux 2023年6月8日
    0136
  • Canal.adapter报错

    Canal.adapter报错 报错如下: 2021-09-09 15:56:33.669 [Thread-12] ERROR c.a.o.canal.adapter.launch…

    Linux 2023年6月8日
    0119
  • Makefile调试和内核定时器的使用

    这周水一篇博客,先把量搞上去。 Makefile简明教程 常用函数 条件函数 $(if condition,then-part[,else-part]) 编写驱动的Makefile…

    Linux 2023年6月7日
    0144
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球