玩转Go语言之闭包

228 阅读5分钟
talk is cheap show me the code!

函数基本使用

1.没形参,没返回值
func say(){   
     fmt.Println("没有返回值没有形参")
}

// 2.有返回值没有形参的函数
// 2.1只有一个返回值的函数
func getNumber()(int)
func getNumber()int{
     return 888
}
func getNumber() (num int){     
num = 999     
return
}

// 2.2有多个返回值的函数
func getValue() (int, int){	
     return 666, 888
}
func getValue() (num int,value int)func getValue() (num ,value int){         
     num = 666         
     value = 888         
     return 666, 888
}
func test()(num int, temp float64, value int)
func test()(num , value int, temp float64){}

// 3.没有返回值有形参的函数
func sum(a int, b int)
func sum(a , b int){
      res := a + b      
      fmt.Println(res)
}

// 4.有返回值有形参的函数
func minus(a, b int)(res int){	
     res = a - b	
     return
}

func minus(a int, b int)(int){        
     res := a - b        
     return res
}

总结:

1.C语言是由函数组成的

2.Go语言也是由函数组成的

3.C语言函数的格式

返回值类型 函数名称(形参列表){
		被控制的语句;
	}

4.Go语言函数的格式

func 函数名称(形参列表)(返回值列表){
		被控制的语句;
	}

5.C语言函数的类型

5.1没有返回值没有形参的函数
5.2有返回值没有形参的函数
5.3没有返回值有形参的函数
5.4有返回值有形参的函数

6.Go语言函数的类型和C语言一样

注意点:

1.在C语言中如果函数的定义写在函数的调用之前必须先声明再调用
在Go语言中如果函数的定义写在函数的调用之前, 不用声明就可以调用, Go语言没有声明
2.Go语言中如果函数只有一个返回值, 那么返回值列表的()可以省略
3.Go语言中如果有返回值, 可以在返回值列表中定义变量, 然后在函数体中直接使用
4.如果在返回值列表中定义了变量,  那么return后面可以不用写任何内容, 默认就会将返回值列表中定义的变量返回
5.Go语言中一个函数可以有多个返回值
6.如果一个函数有多个返回值, 但是我们只想使用其中的一个, 那么可以在接收的时候使用_来忽略, 不需要的那个返回值
7.因为_在Go语言中有特殊的含义, 所以在定义标识符的时候_不能单独作为标识符
8.如果返回值列表中有多个返回值, 并且连续的多个返回值的数据类型都一样, 那么只用在最后一个变量后面添加数据类型即可
9.如果形参列表中有多个形参, 并且连续的多个形参的数据类型都一样, 那么只用在最后一个变量后面添加数据类型即可

传值,与传指针

num := 666
fmt.Println(num)666
change1(num)
fmt.Println(num)666
change2(&num)
fmt.Println(num)789

func change1(a int) {	
     a = 789
}
func change2(a *int) {	
     *a = 789
}
1.在C语言中如果基本数据类型作为函数的参数, 是值传递, 在函数内修改形参不会影响到外界的实参
2.Go语言和C语言一样/ int float bool
3.如果想在函数内部修改外界传入的实参, 那么必须传入指针

匿名函数

C语言中指向函数的指针
int test(int a, int b){}
int (*test)(int, int)
// test相当于找到函数的定义, 然后调用函数test()
// 直接定义一个函数, 然后立即调用这个函数
func(){	
    fmt.Println("匿名函数")
}()
// 定义一个函数类型的变量, 保存匿名函数, 然后通过函数类型的变量调用匿名函数
f := func() {    
    fmt.Println("匿名函数")
}
var f func() = func() {	
    fmt.Println("匿名函数")
}
//fmt.Printf("%T\n", f)
f()

总结:

1.什么是匿名函数?

普通的函数都是有名字的函数, 而匿名函数就是没有名字的函数

2.匿名函数的应用场景:

一般情况下某个函数只会被调用一次, 我们就会使用匿名函数
作为函数的参数, 或者作为函数的返回值

3.注意点:

3.1匿名函数定义之后, 如果没有立即调用, 编译器会报错
3.2也可以将一个匿名函数保存到一个变量中
在C语言中我们知道, 我们可以定义一个指向函数的指针来保存函数的地址, 然后通过指针来调用函数
在Go语言中函数是一等公民(可以定义变量, 作为形参, 作为返回值), 所以在Go语言中也可以用函数类型来定义变量(相当于C语言中指向函数的指针)
3.3由于函数是一等公民, 所以以前定义变量所有的格式, 都可以用于定义函数类型的变量

var 变量名称 函数类型
var 变量名称 函数类型 = 匿名函数
var 变量名称  = 匿名函数
变量名称  := 匿名函数
var(
    var 变量名称  = 匿名函数

)

匿名函数使用场景:

1.作为函数参数

result := calculate(10, 20, func(a, b int) int {       
          return  a + b
})
fmt.Println(result)
func calculate(a, b int, method func(int, int) int) (int) {        
           res := method(a, b)       
           return res
}
2.作为函数的返回值
var fn func(int, int)int
fn = test()
res := fn(10, 20)
fmt.Println(res)
func test()func(int, int)int{	
       return func(a int, b int)int {		
              return a + b	
       }
}

闭包:

1.什么是闭包?

闭包就是一个特殊的匿名函数
只要匿名函数中用到了外界的变量, 那么我们就把匿名函数叫做闭包

注意点:

只要闭包还在使用外界的变量, 那么外界的变量就会一直存在

func addUpper() func() {       
         x := 1        
         return func() {               
                  x++                
                  fmt.Println(x) // 2 , 3 , 4	
          }
}
fn := addUpper()
fn()
fn()
fn()