函数变量
一 函数是第一等公民
go中函数在Go语言中属于“一等公民”,说白了就是可以把函数当变量一样去用,具体如下
1、可以声明函数类型的变量
2、可以赋值
3、可以当做另外一个函数的参数
4、可以当做另外一个函数的返回值
了解:高阶函数指的就是
1、函数可以作为参数
2、函数可以作为返回值
二 可以声明函数类型的变量
我们可以使用type
关键字来定义一个函数类型,具体格式如下:
type calculation func(int,int) int
上面语句定义了一个calculation
类型,它是一种函数类型,这种函数接收两个int类型的参数并且返回一个int类型的返回值,凡是满足该条件的函数都是calculation类型的函数,如下add和sub
func add(x, y int) int{
return x + y
}
func sub(x, y int) int{
return x - y
}
func main() {
fmt.Printf("%T\n",add) // func(int, int) int
fmt.Printf("%T\n",sub) // func(int, int) int
}
三 可以把函数赋值给变量
可以把函数赋值变量,前提是该变量是对应的函数类型
func main() {
var c calculation // 声明一个calculation类型的变量c
c = add // 把add赋值给变量c
fmt.Printf("%T\n", c) // main.calculation
fmt.Println(c(1, 2)) // 像调用add一样调用c
f := add // 将函数add赋值给变量f
fmt.Printf("%T\n", f) // func(int, int) int
fmt.Println(f(10, 20)) // 像调用add一样调用f
}
注意:
函数的类型被称为函数的标识符。如果两个函数形式参数列表和返回值列表中的变量类型一一对应,那么这两个函数被认为有相同的类型和标识符。形参和返回值的变量名不影响函数标识符,也不影响它们是否可以以省略参数类型的形式表示。
// 如下test1与test2的参数名不同,但它们是相同的类型
func test1(x int, y int) (z float64) {
fmt.Println(x,y)
return 1.1
}
func test2(xxx int, yyy int) (zzz float64) {
fmt.Println(xxx,yyy)
return 1.1
}
func main() {
fmt.Printf("%T\n",test1) // func(int, int) float64
fmt.Printf("%T\n",test2) // func(int, int) float64
var f func(int, int) float64
f = test1
f(1,2)
f=test2
f(10,20)
}
四 可以把函数作为参数
type calculation func(int, int) int
func add(x, y int) int {
return x + y
}
func cal1(x, y int, op calculation) int {
return op(x, y)
}
func cal2(x, y int, op func(x, y int) int) int { // 同上述cal1
return op(x, y)
}
func main() {
res1 := cal1(10, 20, add)
fmt.Println(res1) // 30
res2 := cal1(10, 20, add)
fmt.Println(res2) // 30
}
五 可以把函数作为返回值
func do(s string) (func(int, int) int, error) {
switch s {
case "+":
return add, nil
case "-":
return sub, nil
default:
err := errors.New("无法识别的运算符")
return nil, err
}
}
func main() {
f,err:=do("-")
fmt.Println(f,err)
fmt.Println(f(111,222))
}
六 练习
基于函数是第一等公民这一特性,优雅地取代多分支if
func login() {
fmt.Println("要想生活过得去,身上必须背点绿")
}
func register() {
fmt.Println("要想生活过得好,头顶必须长点草")
}
func withdraw() {
fmt.Println("横批:绿毛小乌龟")
}
var funcSlice map[string]func()= map[string]func(){
"登录":login,
"注册":register,
"提现":withdraw,
}
func main() {
//var f func()
var fname string
fmt.Printf("请输入功能名: ")
fmt.Scanln(&fname)
f,ok:=funcSlice[fname]
if ok{
f()
}else {
fmt.Println("输入的功能不存在")
}
}