一 函数签名的概念

​ 一个函数签名 (类型签名,或方法签名) 定义了函数或方法的输入与输出。

​ 简单的说: 函数的签名就是函数的参数列表与返回值列表的统称。使用签名可以鉴别不同函数的特征,此外,也定义了用户与函数直接交互的方法。

​ 特别说明:

​ 1 参数的名称和返回值的名称,不作为函数签名的一部分。换句话说,就是签名与参数的名称无关。

​ 2 只要两个函数参数列表和返回值列表元素的顺序与类型是一致,就可以说明该两个函数是一样的函数或者说实现了同一个类型函数。

​ 例如:

1
2
3
4
5
6
7
8
9
10
11
12
 // 自定义函数类型
type MyFuncType func(int, int) int

// 实现一个和MyFuncType一样类型的函数
func TestFunc (a int, b int) int {
return a + b
}
func main() {
var c MyFuncType = TestFunc
d := c(1, 1)
fmt.Println(d)
}

​ 可以说明TestFunc是对MyFuncType自定义函数类型的一种实现,它们是一种类型的函数。

二 Go中函数是一等的公民

  • 封装代码
  • 分割功能
  • 解耦逻辑
  • 做为普通的值,函数当作参数在其他函数中传递、能将函数赋值变量
  • 能够进行类型判断和转换

三 匿名函数

​ 定义:没有函数名称的函数,称为匿名函数;

​ 1. 匿名函数可以直接复制给变量,然后通过变量进行调用;

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
// 定义匿名函数并将其赋值给anonymous
anonymous := func(say string) {
fmt.Println(say)
}
// 输出anonymous的类型
fmt.Printf("anonymous 的类型:%T\n", anonymous)
// 对赋值后的变量调用
anonymous("function is first class!")
}
输出结果:
anonymous 的类型:func(string)
function is first class!

​ 2. 匿名函数也可以在定义好后的**} 后面直接添加(函数签名)**进行调用

1
2
3
4
5
6
func main() {
// 定义匿名函数并直接调用
func(say string){
fmt.Println(say)
}("hello function!")
}

四 自定义函数类型

​ 使用 type关键词自定义函数类型;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 自定义函数类型
type CustomFunc func(name string, age int)

// 函数SayInfo是对自定义函数的一种实现,函数签名一致
func SayInfo(n string, a int, ) {
fmt.Printf("我的名字叫%v, 年龄%v岁", n, a)
}

func main() {
var customFunc CustomFunc
// 可以进行赋值
customFunc = SayInfo
customFunc("austsxk", 22)

// 对自定义函数定义时,函数签名一定要与自定义函数签名一致,否则编译错误
var Print CustomFunc = func(a string, b int) {
fmt.Println(a, b)
}
Print("austsxk", 22)
}

五 高阶函数

  • 函数作为参数传递
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    package main

    import (
    "errors"
    "fmt"
    )

    // 自定义函数类型,操作类型
    type operate func(x, y int) int

    func Mixer(x, y int, op operate) (int, error) {
    if op == nil {
    return 0, errors.New("操作类型错误")
    }
    return op(x, y), nil
    }

    func main() {
    var op operate = func(x, y int) int {
    return x + y
    }
    var x, y = 23, 43
    // 将函数作为参数,控制函数的行为,将无状态变有状态.只要对operate类型函数进行实现,就可以实现不同逻辑。定向输出。
    result , error := Mixer(x, y, op)
    fmt.Println(result, error)
    }
  • 函数作为返回值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package main

    import (
    "errors"
    "fmt"
    )

    // 定义一个需要返回的函数类型,接受两个int类型参数,返回一个int类型
    type GetValue func(x, y int) (int, error)

    // 自定义操作类型
    type Operate func(x, y int) int

    // 定义一个返回GetValue函数的函数
    func Calculate(op Operate) GetValue {
    return func(x, y int) (int, error) {
    // 如果操作符为nil,则抛出错误
    if op == nil {
    return 0, errors.New("invalid operate error")
    }
    // 否则,调用操作函数
    return op(x, y), nil
    }
    }

    func main() {
    var op = func(x, y int) int{
    return x * y
    }
    var a, b = 5, 10
    result := Calculate(op)
    data, error := result(a, b)
    fmt.Println(data, error)
    }

六 闭包

​ 闭包是在函数中嵌套定义函数,并且在内部函数中,使用到外部函数传入的自由变量,在函数内部获取了访问外部函数参数的权限,并进行逻辑的处理。外部函数返回的一般是内部函数的地址。

​ 例如:

1
2
3
4
5
6
7
8
9
10
11
func Outfunction(x int) func(int) int {
// 闭包将不确定变确定, 使用自由变量
// 内部函数使用了
return func(i int) int {
// 函数内部定义
fmt.Println("\ni=", i)
// 使用外部函数作用域的变量,自由变量
fmt.Println("out func value", x)
return x
}
}

​ 闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不仅要表示数据还要表示代码。将函数作为第一级对象,就是说这些函数可以存储到变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。

七 头等(第一类)函数的使用场景

头等函数就是上面提到的能够支持高阶函数的用法,能够将函数作为其他函数的参数或返回值。

将函数进行传递,根据函数的多样性去确定结果的唯一性。