4.2. 匿名函数

  • 匿名函数-没有函数名字的函数

4.2.1. 1.定义一个匿名函数

匿名函数的定义格式如下:

func(参数列表)(返回参数列表){
函数体
}

匿名函数的定义就是没有名字的普通函数定义

4.2.2. 2.在定义时调用匿名函数

package main

import "fmt"

func main() {
    f := func(data int) {
        fmt.Println("hello world", data)
    }
    f(123)      //hello world 123
}

4.2.3. 3.匿名函数做回调函数

package main

import "fmt"

/*
遍历切片每个元素,通过给定函数进行元素访问
*/
// 使用函数将整个遍历过程进行封装,当要获取切片值时传入一个回调参数即可
func visit(list []int, f func(int)) {
    for _, v := range list {
        f(v)
    }
}

func main() {
    // 使用匿名函数打印切片内容
    visit([]int{1, 2, 3, 4}, func(v int) {
        fmt.Println(v)
    })
}

4.2.4. 4.使用匿名函数实现操作封装

package main

import (
    "flag"
    "fmt"
)

// 定义命令行参数skill,从命理行输入skill,可以将空格后的字符串传入skillParam指针变量
var skillParam = flag.String("skill", "", "skill to perform")

func main() {
    // 解析命令行参数,解析完成后,skillParam指针变量将执行命令行传入的值
    flag.Parse()
    // 定义一个从字符串映射到func()的map,然后填充这个map
    var skill = map[string]func(){
        // 初始化map的键值对,值为匿名函数
        "fire": func() {
            fmt.Println("chicken fire")
        },
        "run": func() {
            fmt.Println("soldier run")
        },
        "fly": func() {
            fmt.Println("angel fly")
        },
    }
    // 使用*skillParam获取命令传递的值,并在map中查找对应命令行参数指定的字符串的函数
    if f, ok := skill[*skillParam]; ok {
        f()
    }else {
        fmt.Println("skill not found")
    }
}
//  go run main.go --skill=run

4.2.5. 5.函数类型实现接口-把函数作为接口来调用

函数和其他类型一样都属于“一等公民”,其他类型能够实现接口,函数也可以。

5.1 结构体实现接口

package main

import "fmt"

type Invoker interface {
    Call(interface{})
}

// 结构体类型,结构体中无须任何成员
type Struct struct {
}

// 实现Invoker的Call,Call()为结构体的方法,该方法是大于from struct和传入的interface{}类型的值
func (s *Struct) Call(p interface{}) {
    fmt.Println("from struct", p)
}
func main() {
    // 声明接口变量
    var invoker Invoker
    // 实例化结构体
    s := new(Struct)
    // 将实例化的结构体赋值到接口
    invoker = s
    // 使用接口调用实例化结构体的方法Struct.Call
    invoker.Call("hello")
}

//from struct hello

4.2.6. 6.总结匿名函数的用法

package main

import "fmt"

// 匿名函数直接赋值函数变量
var sum = func(a, b int) int {
    return a + b
}

func doinput(f func(int, int) int, a, b int) int {
    return f(a, b)
}

// 匿名函数作为返回值
func wrap(op string) func(int, int) int {
    switch op {
    case "add":
        return func(i int, i2 int) int {
            return i + i2
        }
    case "sub":
        return func(i int, i2 int) int {
            return i - i2
        }
    default:
        return nil
    }
}

func main() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()

    sumname := sum(1, 2)
    fmt.Println(sumname)        //3

    // 匿名函数作为实参
    d_name :=doinput(func(i int, i2 int) int {
        return i + i2
    }, 10, 20)
    fmt.Println(d_name)         //30

    name := wrap("add")
    opname := name(5,6)
    fmt.Println(opname)         //11

}

4.2.7. 7.函数体实现接口

函数的声明不能直接实现接口,需要将函数定义为类型后,使用类型实现结构体。 当类型方法被调用时,还需要调用函数本体。

package main

import "fmt"

// 调用器接口
type Invoker interface {
    Call(interface{})
}

// 函数定义为类型
type FuncCaller func(interface{})

// 实现Invoker的Call方法
func (f FuncCaller) Call(p interface{}) {
    // 调用f()函数本体
    f(p)
}


func main() {
    // 声明接口变量
    var invoker Invoker
    // 将匿名函数转为FuncCaller类型,再赋值给接口
    invoker = FuncCaller(func(v interface{}) {
        fmt.Println("from function", v)
    })
    // 使用接口调用FuncCaller.Call,内部会调用函数本体
    invoker.Call("hello")
}

//from function hello

4.2.8. 8.Golang匿名函数更多用法

可赋值给变量,做为结构字段,或者在 channel 里传送。

package main

func main() {
    name := func() { println("hello world!") }      //hello world!
    name()

    // --- function collection ---
    fns := [](func(x int) int){
        func(x int) int { return x + 1 },
        func(x int) int { return x + 2 },
    }
    println(fns[0](100))        //101
    println(fns[1](200))        //202

    // --- function as field ---
    d := struct {
        fn func() string
    }{
        fn: func() string {return "hello hujianli"},    //hello hujianli
    }
    println(d.fn())

    // --- channel of function ---
    fc := make(chan func() string, 2)
    fc <- func() string { return "Hello, World!" }      //Hello, World!
    println((<-fc)())
}

4.2.9. 9.函数是一等公民

函数作为参数传入

代码示例

package main

import "fmt"

// 加函数
func add(x, y int) int {
    return x + y
}

// 减函数
func sub(x, y int) int {
    return x - y
}

// 定义一个函数类型
type OP func(int, int) int

// 定义一个函数,第一个参数是函数类型OP
func do(f OP, x int, y int) int {
    return f(x, y)
}

func main() {
    x := 10
    y := 20
    fmt.Println(do(sub,x,y))
    fmt.Println(do(add,x,y))
}

函数赋值给函数类型变量

package main

import "fmt"

func add(x, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(20,30)) //50
    function := add
    fmt.Println(function(20,30))    //50
}