闭包是一种能够让你用非常舒服的方式来编程的小技巧,Go也支持闭包。

假设从来没有接触过闭包,想在一開始就弄懂什么是闭包(closure)是非常困难的,就像递归一样,直到你真正写过、用过它,你才干真正的对它有一个更详细的认识。

闭包就是一个函数,这个函数包括了执行它所需的上下文环境,这个环境可能是几个变量或者也会是其它的(通常就是变量)。说闭包是一个函数不对,更确切地说。闭包是一个打包了其作用域外部的上下文环境的一段执行环境。假设一时间没有理解这段闭包的含义也不要紧。这是一个循序渐进的过程。

那么我们来看一个网上最通用的解说闭包的样例:

package main

import "fmt"

func A() func() int {
value := 0
return func() int {
value++
return value
} // A()到这里时按理说应该已经销毁掉了局部变量value
} func main() {
B := A()
fmt.Println(B())
fmt.Println(B())
fmt.Println(B())
}

执行结果为:

1
2
3

好好看下这段代码,我们定义一个函数A(),在A中我们又定义了还有一个函数B(),并且B将会作为返回值返回给我们。B的作用就是每次调用都会给A的局部变量value增1。

可是当A函数执行完之后。按理说局部变量value应该已经被销毁了,B无法再对其进行操作,可是从执行结果来看。value却还"活着"。没错,这就是所谓的打包了上下文环境的函数,B就是一个闭包函数,它不仅定义了自己的操作流程,并且附带着它的上文环境A中的value变量。

从这个样例你可能没太看出闭包有什么作用。可是事实上闭包这个东西或多或少会要求编程语言支持匿名函数并且函数在该语言中式第一类型(能够把函数赋值给变量,能够用函数当參数和返回值)。闭包的作用我也不大好说。像JS这种缺陷比較多的语言使用闭包能够带来保护变量的訪问权限、更好的模块化这种优点,而对于Go,我认为闭包最大的优点就是:

1. 不用特意给某个函数取名字了。省事儿~

2. 能够把某个暂时使用的函数定义在近期的地方

3. 和goroutine使用的时候能够直接用go func() {...}() 这种写法。这就不用把每一个要并发的函数都在当前执行环境的外部预先定义一遍了。

讲完了闭包的基本内容。接下来就讲一讲使用闭包时应该注意的问题了。

原则上讲,闭包用起来的最大优点就是方便,可是不要在不论什么情况下都首先想到使用闭包,由于假设你对闭包缺乏了解。那你写出的代码非常可能会有意外的执行效果。来看一下以下的样例:

package main

import (
"fmt"
) func main() {
done := make(chan bool, 3)
for i := 0; i < 3; i++ {
go func() { //这里是有问题的。每一个routine都打包了外层执行环境中的变量i
fmt.Println(i)
done <- true
}()
}
for i := 0; i < 3; i++ {
<-done
}
}

执行结果是:

3
3
3

假设你细致看下代码的话,应该会认为代码看上去没有不论什么问题。可是结果为甚不是1 2 3呢???事实上Go的官方指南也给出了相关的样例让开发人员们注意闭包和goroutine一起使用时要注意的这个问题。

这个样例中事实上第一个循环中的三个goroutine在创建之后都不会立马执行,由于在他们都绑定了外层执行环境中的变量i,由于外层的执行环境随时会更改i的值。所以知道这个循环结束。三个routine都不能開始执行

这时的解决的方法就是把要用到的外层上下文环境作为參数传递给闭包函数。像这样:

package main

import (
"fmt"
) func main() {
done := make(chan bool, 3)
for i := 0; i < 3; i++ {
go func(index int) { // 把外层环境中的i当做參数传进来
fmt.Println(index)
done <- true
}(i) // 把i传进去
}
for i := 0; i < 3; i++ {
<-done
}
}

这种话闭包函数就不须要再绑定外层环境中的那个变量i了。这个问题一定要注意,由于Go里会常常将goroutine和闭包配合使用,假设没有处理好上下文打包的问题,就非常可能引发意外的执行效果。

假设转载,请注明出处:http://blog.csdn.net/gophers

闭包(closure)与协程共用时要注意的事情的更多相关文章

  1. Unity 协程运行时的监控和优化

    我是快乐的搬运工: http://gulu-dev.com/post/perf_assist/2016-12-20-unity-coroutine-optimizing#toc_0 --------- ...

  2. Project Loom:Reactive模型和协程进行时(翻译)

    Java 15将发布Project Loom的第一个版本.我相信这将改变JVM.在这篇文章中,我想深入探讨一下导致我相信这一点的原因. 首先,我们需要了解核心问题.然后,我将尝试描述以前的技术如何解决 ...

  3. 【Python】【容器 | 迭代对象 | 迭代器 | 生成器 | 生成器表达式 | 协程 | 期物 | 任务】

    Python 的 asyncio 类似于 C++ 的 Boost.Asio. 所谓「异步 IO」,就是你发起一个 IO 操作,却不用等它结束,你可以继续做其他事情,当它结束时,你会得到通知. Asyn ...

  4. 协程概念,原理及实现(c++和node.js实现)

    协程 什么是协程 wikipedia 的定义: 协程是一个无优先级的子程序调度组件,允许子程序在特点的地方挂起恢复. 线程包含于进程,协程包含于线程.只要内存足够,一个线程中可以有任意多个协程,但某一 ...

  5. Lua的协程和协程库详解

    我们首先介绍一下什么是协程.然后详细介绍一下coroutine库,然后介绍一下协程的简单用法,最后介绍一下协程的复杂用法. 一.协程是什么? (1)线程 首先复习一下多线程.我们都知道线程——Thre ...

  6. 从Erlang进程看协程思想

    从Erlang进程看协程思想 多核慢慢火了以后,协程类编程也开始越来越火了.比较有代表性的有Go的goroutine.Erlang的Erlang进程.Scala的actor.windows下的fibr ...

  7. [转载]Python 3.5 协程究竟是个啥

    http://blog.rainy.im/2016/03/10/how-the-heck-does-async-await-work-in-python-3-5/ [译] Python 3.5 协程究 ...

  8. 第十天 多进程、协程(multiprocessing、greenlet、gevent、gevent.monkey、select、selector)

    1.多进程实现方式(类似于多线程) import multiprocessing import time,threading def thread_run():#定义一个线程函数 print(&quo ...

  9. [转]-Lua协程的实现

    协程是个很好的东西,它能做的事情与线程相似,区别在于:协程是使用者可控的,有API给使用者来暂停和继续执行,而线程由操作系统内核控制:另 外,协程也更加轻量级.这样,在遇到某些可能阻塞的操作时,可以使 ...

随机推荐

  1. USACO 1.2 Transformations (模拟)

    模拟题目,依照题目给定的要求变换图形就可以,变换的优先级依次减小. 这个题目我写的非常乱.只是最还还是勉强能够执行 /* ID:twd30651 PROG:transform LANG:C++ */ ...

  2. struts自己定义拦截器--登录权限控制

    说明:该自己定义的拦截器实现用户登录的权限控制. login.jsp--->LoginAction--重定向-->MainAction--->main.jsp 一.1.整体的步骤: ...

  3. Android - 使用JD-GUI反编译Android代码

    使用JD-GUI反编译Android代码 本文地址: http://blog.csdn.net/caroline_wendy Android程序出现Bug时,须要依据Bug寻找问题出错的地方; 须要使 ...

  4. 存储概念解析:NAS与SAN的区别

    目前存储网络技术领域中的两个主旋律是SAN(存储区域网络)和NAS(网络连接区域存储),两者都宣称是解决现代企业高容量数据存储需求的最佳选择. 正如在餐厅就餐时大厨不会为您传菜,跑堂不会为您烹制鲜橙烩 ...

  5. angular 兼容ie11 ie11兼容

    兼容一(new Date()用法) new Date('2018-01-01 00:00:00').getHours(); new Date('2018-01-01 00:00:00').getMin ...

  6. [十二省联考2019] 异或粽子 解题报告 (可持久化Trie+堆)

    interlinkage: https://www.luogu.org/problemnew/show/P5283 description: solution: 显然有$O(n^2)$的做法,前缀和优 ...

  7. https://blog.csdn.net/sxf359/article/details/71082404

    https://blog.csdn.net/sxf359/article/details/71082404

  8. uva 11300 Spreading the Wealth_数学推倒 + 思维

    这道题和负载平衡问题是同一道题, 如果 n<=100n <= 100n<=100 的话是可以用最小费用流来求解的. 但是题中 nnn 最大可达到 10610^6106, 这就需要我们 ...

  9. Pyhton学习——Day41

    #一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:# 核心(ECMAScript)# 文档对象模型(DOM) Document object model (整合js,css,ht ...

  10. C语言基本语法——结构体、联合和枚举

    一.结构体 1.什么是结构体 2.结构体语法格式 3.结构体所占内存空间 4.结构体成员赋值 二.联合 1.什么是联合 2.联合语法格式 三.枚举 1.什么是枚举 2.枚举语法格式 一.结构体 1.什 ...