内容简介:在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函数匿名函数
- 纯函数:函数式编程入门
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入浅出Ajax
(美)Brett McLaughlin / 东南大学出版社 / 2006-5 / 98.00元
本书将教会您如何在很短的时间内掌握使用JavaScript代码来向服务器提交异步请求?同时,您可以学习如何使用诸如动态HTML、XML、JSON、DOM等技术来解决开发过程中遇到的许多问题。让你从那些繁琐而笨拙的网站开发技术中彻底解放出来!本书将是一本指导您进行异步开发的经典参考书籍。 作为一名网站设计人员,您也许时常因为遇到以下情况而烦恼:用户只是移动了鼠标就要从服务器重载数据......一起来看看 《深入浅出Ajax》 这本书的介绍吧!