欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Go 学习笔记(16)— 函数(02)[函数类型、有名函数、匿名函数、调用匿名函数、匿名函数赋值给变量、匿名函数做回调函数]

程序员文章站 2022-03-08 23:31:58
...

1. 函数类型


函数类型也叫做函数签名,可以使用 fmt.Printf("%T") 格式化参数打印函数类型。

package main

import "fmt"

func sumTwo(a []int) (ret int) {
	for _, v := range a {
		ret += v
	}
	return
}
func main() {
	n := []int{1, 2, 3, 4, 5}
	result := sumTwo(n) 
	fmt.Println("result is ", result)	// result is  15

	fmt.Printf("sumTwo type is %T\n", sumTwo) // sumTwo type is func([]int) int

}


两个函数类型相同的条件是:拥有相同的形参列表和返回值列表,其中列表元素的次序、个数和类型都相同,形参名称可以不相同。

2. 有名函数


有名函数是指函数有具体的名称,有名函数的函数名可以看作函数类型的常量,可以直接使用函数名调用函数,也可以直接赋值给函数类型变量,可以通过该变量来调用该函数。

package main

import "fmt"

func sum(a, b int) int {
	fmt.Println("I am in sum function")
	return a + b
}

func main() {
	sum(3, 10)	// 直接调用
	result := sum(3, 4)
	fmt.Println("result is ", result)
	f := sum	// 有名函数可以直接赋值给变量
	ret := f(3, 10)	// 通过该变量来调用该函数
	fmt.Println("ret is ", ret)
}

3. 匿名函数


匿名函数是指不需要定义函数名的一种函数实现方式,由一个不带函数名的函数声明和函数体组成。

匿名函数顾名思义就是函数没有名称,匿名函数可以直接赋值给变量,可以当作实参,也可以作为返回值,还可以直接被调用。


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

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

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

3.1 在定义时调用匿名函数


匿名函数可以在声明后调用,例如:

func main() {
	func(data int) {
		fmt.Println("hello", data)
	}(100)	// }后的(100),表示对匿名函数进行调用,传递参数为 100。
}

3.2 将匿名函数赋值给变量


匿名函数可以被赋值,例如:

// 将匿名函数体保存到f()中
f := func(data int) {
    fmt.Println("hello", data)
}

// 使用f()调用
f(100)

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)
	})
}


### 3.4 匿名函数实现操作封装


下面这段代码将匿名函数作为 map 的键值,通过命令行参数动态调用匿名函数,代码如下:

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(){
		"fire": func() {	// 初始化 map 的键值对,值为匿名函数。
			fmt.Println("chicken fire")
		},
		"run": func() {
			fmt.Println("soldier run")
		},
		"fly": func() {
			fmt.Println("angel fly")
		},
	}
/* skillParam 是一个 *string 类型的指针变量,
使用 *skillParam 获取到命令行传过来的值,并在 map 中查找对应命令行参数指定的字符串的函数。
*/
	if f, ok := skill[*skillParam]; ok {
		f()
	} else {
		fmt.Println("skill not found")
	}

}


运行结果如下:

PS D:\code> go run main.go --skill=fly
angel fly
PS D:\code> go run main.go --skill=run
soldier run 

3.5 匿名函数其它示例

package main

import "fmt"

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

// 匿名函数作为返回值
func swap(str string) func(int, int) int {
	if str == "add" {
		return func(a, b int) int {
			return a + b
		}
	}
	if str == "sub" {
		return func(a, b int) int {
			return a - b
		}
	}
	return nil

}

func input(f func(int, int) int, a, b int) int {
	return f(a, b)
}
func main() {
	// 匿名函数作为实参
	z := input(func(x, y int) int {
		return x + y
	}, 10, 20)

	fmt.Println("z is ", z)
	fmt.Println("sum(1, 3) is ", sum(1, 3))
	fmt.Println("swap(1, 3) is ", swap("sub")(1, 10))

}


输出:

z is  30
sum(1, 3) is  4
swap(1, 3) is  -9


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

package main

func main() {
	// --- function variable ---
	fn := func() { println("Hello, World!") }
	fn()
	// --- 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))
	// --- function as field ---
	d := struct {
		fn func() string
	}{
		fn: func() string { return "Hello, World!" },
	}
	println(d.fn())
	// --- channel of function ---
	fc := make(chan func() string, 2)
	fc <- func() string { return "Hello, World!" }
	println((<-fc)())
}


输出:

Hello, World!
101
Hello, World!
Hello, World!
相关标签: Go