golang 函数( 匿名函数,回调函数,高阶函数)

函数的本质

在go语言中,函数也是一种数据类型

Go语言的数据类型:

  • 数值类型:整数,浮点
    进行运算操作,加减乘除,打印
  • 字符串:
    可以获取单个字符,截取子串,遍历,strings包下的函数操作。。
  • 数组,切片,map。
    存储数据,修改数据,获取数据,遍历数据。。。
  • 函数:
    加(),进行调用
  • 注意点:
    函数作为一种复合数据类型,可以看做是一种特殊的变量。
    函数名():将函数进行调用,函数中的代码会全部执行,然后将return的结果返回给调用处
    函数名:指向函数体的内存地址
package main
import "fmt"
func main() {
    // 整型
    a := 10
    // 运算
    a += 5
    fmt.Println("a:", a) // a: 15

    // 数组 切片 map 容器
    b := [5]int{1, 2, 3, 4, 5}
    b[0] = 100
    for i := 0; i < len(b); i++ {
        fmt.Println(b[i]) // [100 2 3 4 5]
    }
    
    c := fun1 // 将fun1多值(函数体的地址)赋值给c
    fmt.Println(c)  // 0x10a4c40
    
    res1 := fun2 // 将fun2的值(函数的地址)赋值给res1,res1和fun2指向同一个函数体
    res2 := fun2(1, 2) // 将fun2函数进行调用,将函数的执行结果赋值给res2,相当于:a+b
    fmt.Println(res1)    // 0x10a4d40
    fmt.Println(res2)    // 3
    
    fmt.Println(res1(10, 20)) // 也可以被调用   30
}
func fun1(a, b int) {
    fmt.Printf("a:%d, b:%d\n", a, b)
}

func fun2(a, b int) int {
    return a + b
}
复制代码

结果:

image.png

匿名函数

定义一个匿名函数,直接进行调用。通常只能使用一次。也可以使用匿名函数赋值给某个函数变量,那么就可以调用多次了

/*
    匿名:没有名字
        匿名函数:没有名字的函数。

    定义一个匿名函数,直接进行调用。通常只能使用一次。也可以使用匿名函数赋值给某个函数变量,那么就可以调用多次了。

    匿名函数:
        Go语言是支持函数式编程:
        1.将匿名函数作为另一个函数的参数,回调函数
        2.将匿名函数作为另一个函数的返回值,可以形成闭包结构。
     */
复制代码

示例代码:

package main
import "fmt"

func main() {
    fun1()
    fun2 := fun1
    fun2()
    
    // 匿名函数 自执行函数
    func() {
        fmt.Println("我是一个匿名函数")
    }()
    
    fun3 := func() {
        fmt.Println("我也是一个匿名函数")
    }
    fun3()
    
    // 定义带参数的匿名函数
    func(a, b int) {
        fmt.Println(a, b)
    }(1, 2)
    
    // 定义带返回值的匿名函数
    res1 := func(a, b int) int {
        return a + b
    }(10, 20)  // 匿名函数被调用了,将执行结果传给res1
    fmt.Println(res1)
    
    res2 := func(a, b int)int {
        return a + b
    }  // 将匿名函数的值,赋值给res2
    fmt.Println(res2)
    
    fmt.Println(res2(100, 200))
}

func fun1() {
    fmt.Println("我是fun1()函数")
}
复制代码

结果:

image.png

匿名函数:go语言是支持函数式编程:

  1. 将匿名函数作为另一个函数的参数,回调参数
  2. 将匿名函数作为另一个函数的返回值,可以形成闭包结构

回调参数

回调参数: callback,就是将一个函数fun2作为函数fun1的一个参数,那么fun2叫做回调函数,fun1叫做高阶函数

/*
高阶函数:
    根据go语言的数据类型的特点,可以将一个函数作为另一个函数的参数。

fun1(),fun2()
将fun2函数作为了fun1这个函数的参数。

        fun1函数:就叫高阶函数
            接收了一个函数作为参数的函数,高阶函数

        fun2函数:回调函数
            作为另一个函数的参数的函数,叫做回调函数。
 */
复制代码

示例代码:

package main

import "fmt"

func main() {
    //设计一个函数,用于求两个整数的加减乘除运算
    fmt.Printf("%T\n", add)  //func(int, int) int
    fmt.Printf("%T\n", oper) //func(int, int, func(int, int) int) int

    res1 := add(1, 2)
    fmt.Println(res1)

    res2 := oper(10, 20, add)
    fmt.Println(res2)

    res3 := oper(5,2,sub)
    fmt.Println(res3)

    fun1:=func(a,b int)int{
        return a * b
    }

    res4:=oper(10,4,fun1)
    fmt.Println(res4)

    res5 := oper(100,8,func(a,b int)int{
        if b == 0{
            fmt.Println("除数不能为零")
            return 0
        }
        return a / b
    })
    fmt.Println(res5)

}
func oper(a, b int, fun func(int, int) int) int {
    fmt.Println(a, b, fun) //打印3个参数
    res := fun(a, b)
    return res
}

//加法运算
func add(a, b int) int {
    return a + b
}

//减法
func sub(a, b int) int {
    return a - b
}
复制代码

image.png

闭包

一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量(外层函数中的参数,或者外层函数中直接定义的变量),并且该外层函数的返回值就是这个内层函数。

这个内层函数和外层函数的局部变量,统称为闭包结构。

首先他是一个函数,是函数与函数外部数据的引用(在函数体内部引用到了函数体外部的数据)

/*
go语言支持函数式编程:
    支持将一个函数作为另一个函数的参数,
    也支持将一个函数作为另一个函数的返回值。

闭包(closure):
    一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量(外层函数中的参数,或者外层函数中直接定义的变量),并且该外层函数的返回值就是这个内层函数。

    这个内层函数和外层函数的局部变量,统称为闭包结构。

    局部变量的生命周期会发生改变,正常的局部变量随着函数调用而创建,随着函数的结束而销毁。
    但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还要继续使用。
 */
复制代码

示例代码:

package main
import "fmt"

func main() {
     res1 := increment() //res1 = fun
     fmt.Printf("%T\n",res1) //func() int
     fmt.Println(res1)
     v1 := res1()
     fmt.Println(v1) //1
     v2 := res1()
     fmt.Println(v2) //2
     fmt.Println(res1())
     fmt.Println(res1())
     fmt.Println(res1())
     fmt.Println(res1())

     res2 := increment()
     fmt.Println(res2)
     v3 :=res2()
     fmt.Println(v3) //1
     fmt.Println(res2())
     fmt.Println(res1())
}

func increment()func()int{ //外层函数
    //1.定义了一个局部变量
    i := 0
    //2.定义了一个匿名函数,给变量自增并返回
    fun := func ()int{ //内层函数
        i++
        return i
    }
    //3.返回该匿名函数
    return fun
}
复制代码

image.png

闭包结构的注意点:局部变量的生命周期会发生改变,正常的局部变量随着函数调用而创建,随着函数的结束而销毁。但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还要继续使用。

  • 实例演示 以一个例子来定义一个闭包,该闭包函数每调用一次,让值加1
func clousure() func(int64) int64 {
     var step int64 = 0
     return func(_step int64) int64 {
          //函数内部引用函数外部的数据
       step +=  _step
       return step
     }
}

func2 := clousure()
    fmt.Println(func2(1))
    fmt.Println(func2(2))
    fmt.Println(func2(3))
复制代码

分析执行结果

闭包函数每次调用,均保留上次的执行结果,并参与下一次调用时候的运算

同一个包中,函数不支持重载即不能有相同的函数名

值类型、引用类型做为参数调用

  1. 数组,值类型
  2. 切片/map,引用类型
  3. 以值类型传递参数,是对应值的拷贝,不会改变实参的值
  4. 以引用类型传递参数,传递的是对应的地址,这个地址占用的空间是轻量级的,对内存占用是极少的,可以通过指针传递的方式,传递一个何种较大的数据,会改变实参的值
 
posted @ 2023-02-21 15:44  易先讯  阅读(384)  评论(0编辑  收藏  举报