内容简介:在Go语言中,函数是一等(first-class)公民,函数类型也是一等的数据类型。函数不但可以用于封装代码、分割功能、解耦逻辑,还可以化身为普通的值,在其他函数间传递、赋予变量、做类型判断和转换等等。函数值可以由此成为能够被随意传播的独立逻辑组件(或者说功能模块)。开头说的,函数是一等公民,函数类型是一等数据类型:
函数
在 Go 语言中,函数是一等(first-class)公民,函数类型也是一等的数据类型。
函数不但可以用于封装代码、分割功能、解耦逻辑,还可以化身为普通的值,在其他函数间传递、赋予变量、做类型判断和转换等等。函数值可以由此成为能够被随意传播的独立逻辑组件(或者说功能模块)。
一等公民
开头说的,函数是一等公民,函数类型是一等数据类型:
package main import "fmt" type calcFunc func(int, int) int func add(x, y int) int { return x + y } func sub(x, y int) int { return x - y } func main() { var f1, f2 calcFunc f1, f2 = add, sub fmt.Println(f1(1, 2)) fmt.Println(f2(100, 50)) }
这里,先声明了一个函数类型。在下面声明的两个函数的前面与caleFunc是一致的。因此都是caleFunc的一个实现。在main函数中,分别把两个函数赋值给caleFunc类型的变量f1和f2,然后可以调用它们。
这里书写 函数签名 的方式与函数声明的是一致的。只是紧挨在参数列表左边的不是函数名称,而是关键字func。这里函数名称和func互换了一下位置而已。
函数签名,就是函数的参数列表和结果列表的统称,它定义了可用来鉴别不同函数的那些特征,同时也定义了我们与函数交互的方式。
“函数是一等的公民”是函数式编程(functional programming)的重要特征。Go语言在语言层面支持了函数式编程。
高阶函数
高阶函数可能具有如下两个特点:
- 接收其他的函数作为参数传入
- 把其他的函数作为结果返回
函数只要满足了上面的任意一个特点,就可以说这个函数是一个高阶函数。高阶函数也是函数式编程中的重要概念和特征。
在上面的例子的基础上,写一个高阶函数,然后再main主函数里调用执行:
package main import ( "errors" "fmt" ) type calcFunc func(int, int) int func add(x, y int) int { return x + y } func sub(x, y int) int { return x - y } func calculate(x, y int, f calcFunc) (int, error) { if f == nil { return 0, errors.New("invalid calcFunc") } return f(x, y), nil } func main() { res, err := calculate(1, 2, add) if err != nil { fmt.Println("ERROR:", err) } fmt.Println("Result:", res) }
上面的calculate就是一个高阶函数,“接收其他的函数作为参数传入”的这种高阶函数。下面的示例是另外一种高阶函数“把其他的函数作为结果返回”:
package main import ( "errors" "fmt" ) type calcFunc func(int, int) int func add(x, y int) int { return x + y } func sub(x, y int) int { return x - y } type resFunc func(int, int) (int, error) func genCalculator(f calcFunc) resFunc { return func(x, y int) (int, error) { if f == nil { return 0, errors.New("invalid calcFunc") } return f(x, y), nil } } func main() { f := genCalculator(sub) res, _ := f(10, 6) fmt.Println("Result:", res) }
闭包
自由变量,在一个函数中存在对外来标识符的引用。所谓的外来标识符,是既不代表当前函数的任何参数或结果,也不是函数内部声明的,它是直接从外边拿过来的。
上面的例子中的genCalculator函数内部,实际上就实现了一个闭包。而genCalculator函数也是一个高阶函数:
func genCalculator(f calcFunc) resFunc { return func(x, y int) (int, error) { if f == nil { return 0, errors.New("invalid calcFunc") } return f(x, y), nil } }
genCalculator函数只做了一件事,那就是定义一个匿名的函数并把它作为结果值返回。而这个匿名的函数就是一个闭包函数。它里面使用的变量f既不代表它的任何参数或结果也不是它自己声明的,而是定义它的genCalculator函数的参数,所以是一个自由变量。而自由变量具体是什么,并不是在定义闭包的时候确定的,而是在genCalculator函数被调用的时候确定的。
函数是Go语言支持函数式编程的主要体现。我们可以通过“把函数传给函数”以及“让函数返回函数”来编写高阶函数,也可以用高阶函数来实现闭包,并以此做到部分程序逻辑的动态生成。
最后,还有一个闭包的典型例子:
package main import "fmt" func increment () func() { var x int return func () { x ++ fmt.Println(x) } } func main() { f := increment() f() // 打印1 f() // 打印2 f() // 打印3 }
主函数里,每次调用执行的结果都会变化。变量x属于闭包的一部分,但是是在闭包的函数外的,每次调用闭包后的x的状态都会保留下来。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Python 拓展之特殊函数(lambda 函数,map 函数,filter 函数,reduce 函数)
- Python 函数调用&定义函数&函数参数
- python基础教程:函数,函数,函数,重要的事说三遍
- C++函数中那些不可以被声明为虚函数的函数
- 017.Python函数匿名函数
- 纯函数:函数式编程入门
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。