闭包基本介绍

闭包就是 一个函数 和其相关的 引用环境 组合的一个整体

好处: 保存引用的变量,下次继续使用,不会销毁

下面通过闭包的方式,写一个数字累加器,体验一下闭包的妙处

闭包实现数字累加

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
}

代码说明

  1. AddUpper是一个函数,返回的数据类型 func(int) int

  2. 闭包的说明

返回的是一个匿名函数,但是这个匿名函数引用到了函数外的变量 n ,因此这个匿名函数就和 n 形成一个整体,构成闭包

  1. 当反复调用 f 函数时,因为 n 只初始化一次,保存了变量的值,因此每调用一次就相当于进行了累加。

  2. 我们要搞清楚闭包,关键就是要分析返回的函数使用到哪些变量

代码分析

这里我引入了一个字符串变量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

从输出可以看出来,闭包引用的变量nstr并没有在调用函数的时候重复声明,而是保留了下次函数调用后更新的值。

闭包案例

需求:

  1. 编写一个函数 makeSuffix(suffix string) ,可以接收一个文件后缀名,并返回一个闭包

  2. 调用闭包,可以传入一个文件名,如果该文件名没有指定后缀,则返回 文件名.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 | 闭包的使用的更多相关文章

  1. 《Web 前端面试指南》1、JavaScript 闭包深入浅出

    闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...

  2. 干货分享:让你分分钟学会 JS 闭包

    闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,很难从定义去理解它.因此,本文不会对闭包的概念进行大篇幅描述 ...

  3. 深入浅出JavaScript之闭包(Closure)

    闭包(closure)是掌握Javascript从人门到深入一个非常重要的门槛,它是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现.下面写下我的学习笔记~ 闭包-无处不 ...

  4. javascript之闭包理解以及应用场景

    半个月没写博文了,最近一直在弄小程序,感觉也没啥好写的. 之前读了js权威指南,也写了篇博文,但是实话实说当初看闭包确实还是一头雾水.现在时隔一个多月(当然这一段时间还是一直有在看闭包的相关知识)理解 ...

  5. js闭包 和 prototype

    function test(){ var p=200; function q(){ return p++; } return q; } var s = test(); alert(s()); aler ...

  6. js闭包for循环总是只执行最后一个值得解决方法

    <style> li{ list-style: none;width:40px;height: 40px;text-align:center;line-height: 40px;curso ...

  7. JavaScript学习笔记(二)——闭包、IIFE、apply、函数与对象

    一.闭包(Closure) 1.1.闭包相关的问题 请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9:方法:找到所有的div, ...

  8. 带你一分钟理解闭包--js面向对象编程

    上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...

  9. 如何设计一门语言(七)——闭包、lambda和interface

    人们都很喜欢讨论闭包这个概念.其实这个概念对于写代码来讲一点用都没有,写代码只需要掌握好lambda表达式和class+interface的语义就行了.基本上只有在写编译器和虚拟机的时候才需要管什么是 ...

  10. JavaScript 闭包深入浅出

    闭包是什么? 闭包是内部函数可以访问外部函数的变量.它可以访问三个作用域:首先可以访问自己的作用域(也就是定义在大括号内的变量),它也能访问外部函数的变量,和它能访问全局变量. 内部函数不仅可以访问外 ...

随机推荐

  1. ProxySQL(8):SQL语句的重写规则

    文章转载自: https://www.cnblogs.com/f-ck-need-u/p/9309760.html 为什么要重写SQL语句 ProxySQL在收到前端发送来的SQL语句后,可以根据已定 ...

  2. Kibana插件

    附加的功能在 Kibana 中是以插件的形式提供的.您可以利用 bin/kibana-plugin 命令来管理这些模块.您也可以手动安装这些插件,只需要将这些插件包放到 plugins 目录并解压到新 ...

  3. git commit 规范

  4. 一文读懂Apache Geode缓存中间件

    目录 一.对缓存中间件的诉求 1.1 我们为什么需要缓存中间件 1.2 缓存的分类 1.1.1 弱势缓存 1.1.2 强势缓存 二.什么是Apache Geode 2.1 Apache Geode的架 ...

  5. 我操作MySQL的惊险一幕

    背景 前几天因工作需要,组长给我安排了一个数据清洗的任务. 任务:把 A 表的数据洗到 B 表. 我的第一反应,什么是「洗」?洗数据是什么?洗钱我倒是知道. 不过我不能慌啊,于是问了问组长. 我:组长 ...

  6. go使用JWT进行跨域认证最全教学

    JWT前言 JWT是JSON Web Token的缩写.JWT本身没有定义任何技术实现,它只是定义了一种基于Token的会话管理的规则,涵盖Token需要包含的标准内容和Token的生成过程. JWT ...

  7. Educational Codeforces Round 106 (Rated for Div. 2)

    就ac了2题... A题一开始题意模模糊糊的似懂非懂,然后自己按样例推出了题意,简单题很容易ac了.还是自己的英语水平太菜了.... B题根据0和1的位置关系能看出来,因为0不能在1后面, 所以有00 ...

  8. spring boot集成redis基础入门

    redis 支持持久化数据,不仅支持key-value类型的数据,还拥有list,set,zset,hash等数据结构的存储. 可以进行master-slave模式的数据备份 更多redis相关文档请 ...

  9. RNN自学理解(一)

    RNN对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,利用了RNN的这种能力,使深度学习模型在解决语音识别.语言模型.机器翻译以及时序分析等NLP领域的问题时有所突破. 参考文献1 ...

  10. 绝杀processOn,这款UML画图神器,阿里字节都用疯了,你还不知道?

    大家好,我是陶朱公Boy,又和大家见面了. 前言 在文章开始前,想先问大家一个问题,大家平时在项目需求评审完后,是直接开始编码了呢?还是会先写详细设计文档,后再开始进行编码开发? ☆现实 这个时候可能 ...