Go | 闭包的使用
闭包基本介绍
闭包就是 一个函数 和其相关的 引用环境 组合的一个整体
好处: 保存引用的变量,下次继续使用,不会销毁
下面通过闭包的方式,写一个数字累加器,体验一下闭包的妙处
闭包实现数字累加
package main
import "fmt"
// 累加器
// 闭包 - 函数柯里化
// 返回值类型: func(int) int
func AddUpper() func(int) int {
var n int = 100
return func(i int) int {
n = n + i
return n
}
}
func main() {
f := AddUpper()
fmt.Println(f(1)) // 101
fmt.Println(f(2)) // 103
fmt.Println(f(3)) // 106
}
代码说明
AddUpper是一个函数,返回的数据类型 func(int) int
闭包的说明

返回的是一个匿名函数,但是这个匿名函数引用到了函数外的变量 n ,因此这个匿名函数就和 n 形成一个整体,构成闭包
当反复调用
f函数时,因为 n 只初始化一次,保存了变量的值,因此每调用一次就相当于进行了累加。我们要搞清楚闭包,关键就是要分析返回的函数使用到哪些变量
代码分析
这里我引入了一个字符串变量str,来帮助分析闭包是怎么保存变量的。
package main
import (
"fmt"
)
// 累加器
// 闭包 - 函数柯里化
// 返回值类型: func(int) int
func AddUpper() func(int) int {
var n int = 100
var str = "hello"
return func(i int) int {
n = n + i
fmt.Println("i=", i)
str += string(36) // ascii 36 = '$'
fmt.Printf("str==%s\n", str)
return n
}
}
func main() {
f := AddUpper()
// fmt.Println(AddUpper()(1)) // 101
fmt.Println("f(1)=", f(1)) // 101
fmt.Println("f(2)=", f(2)) // 103
fmt.Println("f(3)=", f(3)) // 106
}
i= 1
str==hello$
f(1)= 101
i= 2
str==hello$$
f(2)= 103
i= 3
str==hello$$$
f(3)= 106
从输出可以看出来,闭包引用的变量n和str并没有在调用函数的时候重复声明,而是保留了下次函数调用后更新的值。
闭包案例
需求:
编写一个函数 makeSuffix(suffix string) ,可以接收一个文件后缀名,并返回一个闭包
调用闭包,可以传入一个文件名,如果该文件名没有指定后缀,则返回 文件名.jpg ,如果已经有.jpg,则返回原文件名。
strings.HasSuffix,该函数可以判断某个字符串是否有指定的后缀。
上代码
package main
import (
"fmt"
"strings"
)
func makeSuffix(suffix string) func(string) string {
return func(name string) string {
if !strings.HasSuffix(name, suffix) {
return name + suffix
}
return name
}
}
// 传统写法
func makeSuffixV2(suffix string, name string) string {
if !strings.HasSuffix(name, suffix) {
return name + suffix
}
return name
}
func main() {
// 闭包调用
f := makeSuffix(".jpg")
fmt.Println(f("xiao")) // xiao.jpg
fmt.Println(f("xiaoxiao.jpg")) // xiaoxiao.jpg
fmt.Println(f("xiaoxiao.666")) // xiaoxiao.666.jpg
// 传统写法调用
fmt.Println("makeSuffixV2=", makeSuffixV2(".jpg", "allblue")) // makeSuffixV2= allblue.jpg
fmt.Println("makeSuffixV2=", makeSuffixV2(".jpg", "all.blue")) // makeSuffixV2= all.blue.jpg
}
代码说明
返回的匿名函数和 makeSuffix(suffix string) 的 suffix 变量组合成一个闭包
传统写法和闭包写法实现效果一样,但是,传统写法需要重复写变量, 比如上面的
makeSuffixV2(".jpg", "all.blue"))
闭包则解决了这个问题,是代码看起来更加的简洁
闭包的好处之一: 参数复用
好处: 保存引用的变量,下次继续使用,不会销毁
函数柯里化(闭包)
参考我的另一篇文章: 甜点cc的语雀知识库

我是 甜点cc☭
微信公众号:【看见另一种可能】
专注前端开发,也喜欢专研各种跟本职工作关系不大的技术,技术、产品兴趣广泛且浓厚。本号主要致力于分享个人经验总结,希望可以给一小部分人一些微小帮助。
Go | 闭包的使用的更多相关文章
- 《Web 前端面试指南》1、JavaScript 闭包深入浅出
闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...
- 干货分享:让你分分钟学会 JS 闭包
闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,很难从定义去理解它.因此,本文不会对闭包的概念进行大篇幅描述 ...
- 深入浅出JavaScript之闭包(Closure)
闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面写下我的学习笔记~ 闭包-无处不 ...
- javascript之闭包理解以及应用场景
半个月没写博文了,最近一直在弄小程序,感觉也没啥好写的. 之前读了js权威指南,也写了篇博文,但是实话实说当初看闭包确实还是一头雾水.现在时隔一个多月(当然这一段时间还是一直有在看闭包的相关知识)理解 ...
- js闭包 和 prototype
function test(){ var p=200; function q(){ return p++; } return q; } var s = test(); alert(s()); aler ...
- js闭包for循环总是只执行最后一个值得解决方法
<style> li{ list-style: none;width:40px;height: 40px;text-align:center;line-height: 40px;curso ...
- JavaScript学习笔记(二)——闭包、IIFE、apply、函数与对象
一.闭包(Closure) 1.1.闭包相关的问题 请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9:方法:找到所有的div, ...
- 带你一分钟理解闭包--js面向对象编程
上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...
- 如何设计一门语言(七)——闭包、lambda和interface
人们都很喜欢讨论闭包这个概念.其实这个概念对于写代码来讲一点用都没有,写代码只需要掌握好lambda表达式和class+interface的语义就行了.基本上只有在写编译器和虚拟机的时候才需要管什么是 ...
- JavaScript 闭包深入浅出
闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...
随机推荐
- Beats:在Docker里运行Filebeat
- 安装Alertmanager,nginx配置二级路径代理访问
安装配置 Alertmanager wget https://github.com/prometheus/alertmanager/releases/download/v0.20.0/alertman ...
- mongodb停止关闭服务
停止服务的方式有两种:快速关闭和标准关闭,下面依次说明: (一)快速关闭方法(快速,简单,数据可能会出错) 目标:通过系统的kill命令直接杀死进程: 杀完要检查一下,避免有的没有杀掉. #通过进程编 ...
- nginx+gunicorn部署Django项目
实际采用的nginx.conf文件内容: server { charset utf-8; listen 80; server_name ip; access_log /webapps/project/ ...
- NOI2018 D1T1 洛谷P4768 归程 (Kruskal重构树)
实际上是一个最短路问题,但加上了海拔这个条件限制,要在海拔<水位线p中找最短路. 这里使用Kruskal重构树,将其按海拔建成小根堆,我们就可以在树中用倍增找出他不得不下车的点:树中节点有两个权 ...
- Vue 中为什么要有nextTick?
摘要:本文将浅析nextTick的作用.使用场景和背后的原理实现,希望对大家有所帮助. 本文分享自华为云社区<Vue 中的 nextTick 有什么作用?>,作者:CoderBin. 一. ...
- 1.关于SPring Boot项目的创建
一.引入依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spri ...
- 7.httpie
可以使用curl或httpie测试我们的服务器.Httpie是用Python编写的用户友好的http客户端 安装:pip3 install httpie #get请求示例 输入命令:http ht ...
- SpringBoot 自动装配原理
早期的Spring项目需要添加需要配置繁琐的xml,比如MVC.事务.数据库连接等繁琐的配置.Spring Boot的出现就无需这些繁琐的配置,因为Spring Boot基于约定大于配置的理念,在项目 ...
- 我要涨知识 —— TypeScript 常见面试题(一)
1.ts 中的 any 和 unknown 有什么区别? unknown 和 any 的主要区别是 unknown 类型会更加严格:在对 unknown 类型的值执行大多数操作之前,我们必须进行某种形 ...