一、函数的变量作用域和可见性

1.全局变量在main函数执行之前初始化,全局可见

2.局部变量在函数内部或者if、for等语句块有效,使用之后外部不可见

3.全局变量和局部变量同名的情况下,局部变量生效。

4.可见性:

包内任何变量或函数都是能访问的。

包外的话,首字母大写是可以访问的,首字母小写的表示私有的不能被外部调用。

二、匿名函数

1.Go语言中函数也是一种类型,所以可以用一个函数类型的变量进行接收。

func anonyTest1(){
fmt.Println("anonyTest1")
} //将改函数赋值给一个变量f,执行f
func AnonyTest(){
f:= anonyTest1
f()
}

2.匿名函数就是不指定名称的函数,如下就是匿名函数的使用

func AnonyTest2(){
f:= func() {
fmt.Println("AnonyTest2")
}
f() //或者
func() {
fmt.Println("AnonyTest2...")
}() }

3.下面一个例子结合defer来看一下,这三个输出都是什么

func AnonyTest3(){
var i=0
defer func() {
fmt.Printf("defer func i=%v \n",i)
}() defer fmt.Printf("defer i=%v \n",i) for;i<10; i++{
} fmt.Printf("i=%v \n",i)
}

从defer那篇文章我们知道 defer fmt.Printf("defer i=%v \n",i) 打印的就是i初始化后的值,最后一个也一定是for循环之后的值10,

主要就是匿名函数执行之后的值,有意思是10,说明访问了匿名函数外部的i,这就涉及到了闭包

运行结果如下:

i=10
defer i=0
defer func i=10

4.既然函数也是一种类型,那么就可以把函数当做参数进行输入、输出了。(感觉有点类似C#里面的委托)

func Calc(a,b int, op func(int,int)int) int {
return op(a,b)
} func add(a,b int) int{
return a+b
} func sub(a,b int)int{
return a-b
} func AnonyTest4(){ var a = 2
var b = 1 var x = Calc(a,b,add)
var y = Calc(a,b,sub) fmt.Printf("x=%v, y=%v \n",x,y)
}

结果:

x=3, y=1

三、闭包

闭包是由函数和与其相关的引用环境组合而成的实体(好抽象,难理解啊)

func Adder() func(int) int{
var x int
return func(d int) int{
x+=d
return x
}
}

像上面这段代码,我们可以看到定义了一个变量x,以及return中的匿名函数。我们可以看到匿名函数引用了外部的变量x,我们可以把这个x叫做自由变量。

换句话说,这个匿名函数和这个自由变量x组成了一个整体,只要是在这个整体的生命周期内这个x都是有效的。

下面使用一下这个Adder函数:

func ClosureDemo5(){
var f = Adder()
fmt.Printf("结果=%d\n",f(1))
fmt.Printf("结果=%d\n",f(20))
fmt.Printf("结果=%d\n",f(300))
} 

执行结果

结果=1

结果=21

结果=321  

正如上面所提到的,这个只要Addr() 也就是f这个对象没有消亡,那么f中的这个x就始终存在,也就是为什么第二次是21,第三次是321的原因了。

其他例子:

例子1:

func Adder2(base int) func(int)int{
return func(i int) int{
base += i
return base
}
} func main(){
tmp1 := Adder2(10)
fmt.Println(tmp1(1),tmp1(2)) tmp2 := Adder2(100)
fmt.Println(tmp2(10),tmp2(20))
}

这里Adder2接收一个int类型参数base,然后返回一个func,这里这个匿名函数里面引用了这个参数base,那么这个参数base和匿名函数就形成了一个整体。

后面我们 tmp1被赋值为 Adder2(10) ,那么在tmp1这个对象的生命周期内,base是被初始化为10且一直存在,所以结果是 11 和 13,同理后面是 110 和 130

例子2:

func calc(base int) (func(int)int,func(int)int){
add:= func(i int)int{
base +=i
return base
}
sub:= func(i int)int{
base -= i
return base
}
return add,sub
} func main(){
f1,f2 := calc(10)
fmt.Println(f1(1),f2(2))
fmt.Println(f1(3),f2(4))
fmt.Println(f1(5),f2(6))
fmt.Println(f1(7),f2(8))
}

分析一下:

这里base和 add以及sub的匿名函数也组成了一个实体也就是calc,所以在f1和f2的生命周期内,base一直存在,并被初始化成了10.

所以结果就是 f1(1) 就是10+1 =11 而 f2(2)就是 11-2 = 9,其他同理。

所以结果如下:


闭包的副作用!

func main(){
for i:=0;i<5;i++{
go func(x int){
fmt.Println(x)
}(i) }
time.Sleep(time.Second)
}

上述代码应该结果是多少?我的猜想应该是0、1、2、3、4

但是实际结果是:

5
5
5
5
5

为什么会出现这样的情况?实际上面这里每一个go协程中的匿名函数和外部for循环的i也形成了闭包,因为for循环执行比较快,所以go还没来得及执行就变成5了。

我在每一个go协程之后加一个延时,结果就是0,1,2,3,4了。

func main(){
for i:=0;i<5;i++{
go func(){
fmt.Println(i)
}()
time.Sleep(time.Second)
}
time.Sleep(time.Second)
}

结果如下

0
1
2
3
4

问题就在于不可能每次执行都进行延迟吧,所以需要做一件事情打破这个闭包。

func main(){
for i:=;i<;i++{
go func(x int){
fmt.Println(x)
}(i) }
time.Sleep(time.Second)
}

这里把i当做参数传入到匿名函数中,保证了每次循环传的值都不一样。

Go语言中的闭包的更多相关文章

  1. 001_解析go语言中的闭包

    go语言中的闭包,是大家学习go语言的一个大难点,笔者在学习时候也是痛苦不堪,在来回对比了其它语言的用法,并且查阅了很多网上的文章,终于对闭包有了一个较为清晰的认识,以下就是关于闭包的解析 首先看一个 ...

  2. 015_go语言中的闭包

    代码演示 package main import "fmt" func intSeq() func() int { i := 0 return func() int { i++ r ...

  3. [译] Closures in Lua - Lua中的闭包

    原文:(PDF) . 摘要 一等(first-class)函数是一种非常强大的语言结构,并且是函数式语言的基础特性.少数过程式语言由于其基于栈的实现,也支持一等函数.本文讨论了Lua 5.x用于实现一 ...

  4. [转][译] Closures in Lua - Lua中的闭包

    http://www.cnblogs.com/plodsoft/p/5900270.html?utm_source=tuicool&utm_medium=referral 原文:(PDF) . ...

  5. javaScript中的闭包原理 (译)

    这篇文章通过javaScript代码解释了闭包的原理,来让编程人员理解闭包.它不是写给大牛或使用功能性语言进行编程的程序员的.一旦意会了其核心概念,闭包理解起来并不难.然而,你不可能通过阅读任何有关闭 ...

  6. 彻底弄懂js循环中的闭包问题

    来源:http://www.108js.com/article/article1/10177.html?id=899 第一次接触这个问题还是在我刚开始学js的时候,当时就是一头雾水,时隔一年多了,突然 ...

  7. javascript中的闭包解析

    学习javaScript已经有一段时间了,在这段时间里,已经感受到了JavaScript的种种魅力,这是一门神奇的语言,同时也是一门正在逐步完善的语言,相信在大家的逐步修改中,这门语言会逐步的完善下去 ...

  8. 如何在C语言中调用Swift函数

    在Apple官方的<Using Swift with Cocoa and Objectgive-C>一书中详细地介绍了如何在Objective-C中使用Swift的类以及如何在Swift中 ...

  9. js中的闭包之我理解

    闭包是一个比较抽象的概念,尤其是对js新手来说.书上的解释实在是比较晦涩,对我来说也是一样. 但是他也是js能力提升中无法绕过的一环,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的 ...

随机推荐

  1. 从零开始学安全(四十六)●sqli-labs 1-4关 涉及的知识点

    Less-1 到Less-4  基础知识注入 我们可以在 http://127.0.0.1/sqllib/Less-1/?id=1 后面直接添加一个 ‘ ,来看一下效果: 从上述错误当中,我们可以看到 ...

  2. 学JAVA第十二天,今天写java控制台输入流及String的类型转换

    今天老师讲了一天狗跳楼的问题,昨天解开始说了,今天都没讲新课, 所以,今天自学了Scanner类及String的类型转换 先来Scanner类实现键盘输入功能: 代码: package pkg1; i ...

  3. python3 Flask -day2

    flask 实战第二天,url传参 当我们访问网站/的时候,会执行hell_world函数,并把这个函数的返回值返回给浏览器,这样浏览器就显示hello world了 @app.route('/') ...

  4. Yii2设计模式——单例模式

    应用举例 在Yii.php中: require __DIR__ . '/BaseYii.php'; // Yii框架的帮助类,提供框架基本的功能 class Yii extends \yii\Base ...

  5. Django之无名分组,有名分组

    在Django 2.0版本之前,在urls,py文件中,用url设定视图函数 urlpatterns = [ url(r'login/',views.login), ] 其中第一个参数是正则匹配,如下 ...

  6. Parcelable 小记

    Parcelable 类,接口类,用于数据的序列化封装.常见的Bundle,Intent类都实现了该类.   实现该类需要实现writeToParcel和describeContents方法,最后还需 ...

  7. Win10中Vue.js的安装和项目搭建

    一. 提前准备工作 1.Node.js环境 2.Windows10 3.npm(前端包管理工具) 4.webpack(前端资源加载/打包工具) 二. 开始安装 1..下载并安装Node.js 下载地址 ...

  8. 测者的测试技术手册:智能化测试框架EvoSuite的一个坑以及填坑方法

    问题 最近在不断地学习和探索EvoSuite框架的时候,在生产JUnit单元测试框架后,出现如下问题: Exception: Caused by: org.evosuite.runtime.TooMa ...

  9. Hadoop Yarn框架原理解析

    在说Hadoop Yarn的原理之前,我们先来看看Yarn是怎样出现的.在古老的Hadoop1.0中,MapReduce的JobTracker负责了太多的工作,包括资源调度,管理众多的TaskTrac ...

  10. w3wp.exe进程占用内存过高解决方法

    解决CPU占用过多: 1.在IIS中对每个网站进行单独的应用程序池配置.即互相之间不影响. 2.设置应用程序池的CPU监视,不超过25%(服务器为4CPU),每分钟刷新,超过限制时关闭. 根据w3wp ...