【Go语言学习笔记】函数做参数和闭包
函数做参数
在Go语言中,函数也是一种数据类型,我们可以通过type来定义它,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。类似于重写(同名覆盖)。
回调函数:函数有一个参数是函数类型,这个函数就是回调函数。
更准确地说是将一个函数的指针作为参数传递给另一个函数。
而回调函数的定义则是不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
`type FuncType func(int, int) int //声明一个函数类型, func后面没有函数名
//函数中有一个参数类型为函数类型:f FuncType
//回调函数,函数有一个参数是函数类型,这个函数就是回调函数
//计算器,可以进行四则运算
//多态,多种形态,调用同一个接口,不同的表现,可以实现不同表现,加减乘除//现有想法,后面再实现功能
func Calc(a, b int, f FuncType) (result int) {
result = f(a, b) //通过调用f()实现任务
return
}
func Add(a, b int) int {
return a + b
}
func Minus(a, b int) int {
return a - b
}
func main() {
//函数调用,第三个参数为函数名字,此函数的参数,返回值必须和FuncType类型一致
result := Calc(1, 1, Add)
fmt.Println(result) //2
var f FuncType = Minus
fmt.Println("result = ", f(10, 2)) //result = 8
}`
匿名函数
匿名函数是指不需要定义函数名的一种函数实现方式,它并不是一个新概念,最早可以回溯到1958年的Lisp语言。
在Go语言里,所有的匿名函数(Go语言规范中称之为函数字面量)都是闭包。
func main() {
i := 0
str := "mike"
//方式1
f1 := func() { //匿名函数,无参无返回值
//引用到函数外的变量
fmt.Printf("方式1:i = %d, str = %s\n", i, str)
}
f1() //函数调用
//方式1的另一种方式
type FuncType func() //声明函数类型, 无参无返回值
var f2 FuncType = f1
f2() //函数调用
//方式2
var f3 FuncType = func() {
fmt.Printf("方式2:i = %d, str = %s\n", i, str)
}
f3() //函数调用
//方式3
func() { //匿名函数,无参无返回值
fmt.Printf("方式3:i = %d, str = %s\n", i, str)
}() //别忘了后面的(), ()的作用是,此处直接调用此匿名函数
//方式4, 匿名函数,有参有返回值
v := func(a, b int) (result int) {
result = a + b
return
}(1, 1) //别忘了后面的(1, 1), (1, 1)的作用是,此处直接调用此匿名函数, 并传参
fmt.Println("v = ", v)
}
闭包
所谓闭包就是一个函数“捕获”了和它在同一作用域的其它常量和变量。
这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量。
它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用它,这些变量就还会存在。

闭包捕获外部变量特点:
func main() {
i := 10
str := "mike"
func() {
i = 100
str = "go"
//内部:i = 100, str = go
fmt.Printf("内部:i = %d, str = %s\n", i, str)
}() //别忘了后面的(), ()的作用是,此处直接调用此匿名函数
//外部:i = 100, str = go
fmt.Printf("外部:i = %d, str = %s\n", i, str)
}
//一般函数,函数结束了就释放局部变量
func test01() int {
var x int //没有初始化,值为0
x++
return x * x //函数调用完毕,x自动释放
}
func main() {
//返回值为一个匿名函数,返回一个函数类型,通过f来调用返回的匿名函数,f来调用闭包函数
//它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用它,这些变量就还会存在。
test()
f := squares()
fmt.Println(f()) //1
fmt.Println(test01())//1
fmt.Println(test01())//1
fmt.Println(test01())//1
fmt.Println(test01())//1
}`
将返回值改成匿名函数
// squares返回一个匿名函数,func() int
// 该匿名函数每次被调用时都会返回下一个数的平方。
func squares() func() int {
var x int
return func() int {//匿名函数
x++ //捕获外部变量
return x * x
}
}
func main() {
f := squares()
fmt.Println(f()) // "1"
fmt.Println(f()) // "4"
fmt.Println(f()) // "9"
fmt.Println(f()) // "16"
}
函数squares返回另一个类型为 func() int 的函数。对squares的一次调用会生成一个局部变量x并返回一个匿名函数。每次调用时匿名函数时,该函数都会先使x的值加1,再返回x的平方。第二次调用squares时,会生成第二个x变量,并返回一个新的匿名函数。新匿名函数操作的是第二个x变量。
通过这个例子,我们看到变量的生命周期不由它的作用域决定:squares返回后,变量x仍然隐式的存在于f中。
其实本质来说,就跟宏替换一样,把闭包里面的函数体直接替换到外函数就成了这样:
func test(){
var res int //这个变量原来会由系统生成,记录返回值
var x int
x++
res = x * x
fmt.Println(res)
x++
res = x * x
fmt.Println(res)
x++
res = x * x
fmt.Println(res)
x++
res = x * x
fmt.Println(res)
//在这里x才释放
}
【Go语言学习笔记】函数做参数和闭包的更多相关文章
- C语言学习笔记--函数
1. C 语言中的函数 (1)函数的由来: 程序 = 数据 + 算法→C 程序 = 数据 + 函数 (2)模块化程序设计 (3)C 语言中的模块 2. 面向过程的程序设计 (1)面向过程是一种以过程为 ...
- C语言学习笔记--函数与指针
1. 函数类型 (1)C 语言中的函数有自己特定的类型,这个类型由返回值.参数类型和参数个数共同决定.如 int add(int i,int j)的类型为 int(int,int). (2)C 语言中 ...
- Swift 函数做参数和闭包做参数的一个细节差别
函数作参数,示例为传入一个String和一个添加前缀的函数,返回一个添加完前缀的String: func demo(str:String,addPrefix:(String)->String)- ...
- c语言学习笔记 函数数组传递笔记
今天学习c语言的一个小例子,果然还是陷入了php的编程习惯里,这里记录一下. #include <stdio.h> //例子很简单,就是编写一个函数把传递进来的数组里的值都赋值为1而已 / ...
- Go语言学习笔记-函数部分(三)
函数部分 函数基本组成:关键字func.函数名.参数列表.返回值.函数体.返回语句 例子: func Add(int a, int b) (return int, err error){ ....函数 ...
- ES6-11学习笔记--函数的参数
参数的默认值 与解构赋值结合 length属性 作用域 函数的name属性 ES5设置函数参数默认值: function foo(x, y) { y = y || 'world'; console ...
- Go语言学习笔记七: 函数
Go语言学习笔记七: 函数 Go语言有函数还有方法,神奇不.这有点像python了. 函数定义 func function_name( [parameter list] ) [return_types ...
- 大一C语言学习笔记(5)---函数篇-定义函数需要了解注意的地方;定义函数的易错点;详细说明函数的每个组合部分的功能及注意事项
博主学习C语言是通过B站上的<郝斌C语言自学教程>,对于C语言初学者来说,我认为郝斌真的是在全网C语言学习课程中讲的最全面,到位的一个,这个不是真不是博主我吹他哈,大家可以去B站去看看,C ...
- Go语言学习笔记(1)——顺序编程
Go语言学习笔记这一堆主要是<Go语言编程>(人民邮电出版社)的读书笔记.中间会穿插一些零碎的点,比如源码学习之类的.大概就是这样吧. 1. 顺序编程 1.1 变量 变量的声明: var ...
随机推荐
- Docker系列(18)- 具名挂载和匿名挂载
容器数据卷挂载方式 容器的数据卷可以看成就是容器的挂载方式:一个宿主机有多个容器,多个容器挂载方式不同,因此宿主机就有多个卷 每一个挂载方式在宿主机上都有一个名称,即卷名 宿主机如何查看这些卷,对使用 ...
- P1074 [NOIP2009 提高组] 靶形数独
#include<bits/stdc++.h> using namespace std; const int N=10; int a[N][N],ans[N][N],vis[3][N][N ...
- iPhone发布内测程序的方法
iPhone是封闭系统,不像android手机可以自行安装apk,所以iPhone手机发布内测程序相对来说复杂一些. 越狱安装 如果测试用户的机器已经越狱,那就简单了,直接打包成ipa,用户直接通过9 ...
- @RestController的用法
我一直都不太理解RESTFUL风格但是先记住一些基本用法在深入吧 ** * * 在服务端应用程序状态和功能可以分成各种资源,每一个资源都使用URL 得到一个唯一的地址,所有资源都共享统一的 * 接口, ...
- PolarDB PostgreSQL Buffer Management 原理
背景介绍 传统数据库的主备架构,主备有各自的存储,备节点回放WAL日志并读写自己的存储,主备节点在存储层没有耦合.PolarDB的实现是基于共享存储的一写多读架构,主备使用共享存储中的一份数据.读写节 ...
- oeasy教您玩转vim - 53 - # 批量替换
查找细节 回忆上节课内容 我们温习了关于搜索的相关内容 /正向,?反向 n保持方向,N改变方向 可以设置 是否忽略大写小写 是否从头开始查找 是否高亮显示 还有一些正则表达式的使用方法 行头行尾 ^$ ...
- FastAPI 学习之路(十二)接口几个额外信息和额外数据类型
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- JDK 8中重要的函数式接口(必知必会)
JDK 8 提供的重要函数式接口: Consumer (消费者) 功能:接收一个对象,返回void. 定义:void accept(T t) 默认方法:Consumer andThen(Consume ...
- 【二食堂】Beta - Scrum Meeting 8
Scrum Meeting 8 例会时间:5.22 20:00~20:10 进度情况 组员 当前进度 今日任务 李健 1. UI优化已经完成,顺带修复了一点小bug.issue 1. 文本导入.保存部 ...
- 了解 js 堆内存 、栈内存 。
js中的堆内存与栈内存 在js引擎中对变量的存储主要有两种位置,堆内存和栈内存. 和java中对内存的处理类似,栈内存主要用于存储各种基本类型的变量,包括Boolean.Number.String.U ...