Go36-12-函数

栏目: Go · 发布时间: 5年前

内容简介:在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的状态都会保留下来。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数学之美

数学之美

吴军 / 人民邮电出版社 / 2012-5-1 / 45.00元

几年前,“数学之美”系列文章原刊载于谷歌黑板报,获得上百万次点击,得到读者高度评价。读者说,读了“数学之美”,才发现大学时学的数学知识,比如马尔可夫链、矩阵计算,甚至余弦函数原来都如此亲切,并且栩栩如生,才发现自然语言和信息处理这么有趣。 今年,作者吴军博士几乎把所有文章都重写了一遍,为的是把高深的数学原理讲得更加通俗易懂,让非专业读者也能领略数学的魅力。读者通过具体的例子学到的是思考问题的......一起来看看 《数学之美》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试