go语言学习(11)--闭包与函数式编程

栏目: 编程语言 · 发布时间: 5年前

内容简介:通过一个累加器来看闭包的概念fun1返回的不是一个值,而是一个函数 fun2,a = fun2,所以 a(i)会打印 sum 的值,为什么 sum 一直在加呢,函数里的值为什么可以带到函数体外呢,这就是闭包的神奇之处,闭包是离散数学的一个概念,可以多看看网上的讲解加深印象其实可以把闭包看做一个类, sum 就是类里的属性, fun2就是类的方法

闭包

通过一个累加器来看闭包的概念

python 闭包

def fun1():
    sum = 0
    def fun2(v):
        nonlocal sum
        sum += v
        return sum
    return fun2
    
a = fun1()
for i in range(10):
    print(a(i))

fun1返回的不是一个值,而是一个函数 fun2,a = fun2,所以 a(i)会打印 sum 的值,为什么 sum 一直在加呢,函数里的值为什么可以带到函数体外呢,这就是闭包的神奇之处,闭包是离散数学的一个概念,可以多看看网上的讲解加深印象

其实可以把闭包看做一个类, sum 就是类里的属性, fun2就是类的方法

所以 fun2可以使用 sum(自由变量)

java 闭包

static Function<Integer, Integer> adder() {
        final Holder<Integer> sum = new Holder<>(0);
        return (Integer value) -> {
            sum.value += value;
            return sum.value;
        };
    }

public static void main(String[] args) {
    Function a = adder();
    for (int i = 0; i < 10; i++) {
        System.out.println(a.apply(i));
    }
}

java 里函数不能像变量一样传递,但也能模拟闭包这里的 adder 其实是一个 Function 对象

上面 python 代码里 sum 前有个 nonlocal 修饰,表明 sum 不是一个局部变量,这里直接用了 final 修饰

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁

go 闭包

func adder() func(int) int {
    sum := 0
    return func(v int) int {
        sum += v
        return sum
    }
}

但是正统的函数式编程不是这样,函数其实是一个系统,我们只关心,入参(x)和返回值(y)是什么,其实里面是怎么实现的我们并不关心,现代的很多业务代码,其实在函数体内做了很多事情,创造了很多变量和对象,这其实被称为函数的'副作用'

还是看累加器

// 正统的函数式编程
// 只有常量和函数
type iAdder func(int) (int, iAdder)

func adder2(base int) iAdder {
    return func(i int) (int, iAdder) {
        return base + i, adder2(base + i)
    }
}

func main(){
    a := adder2(0)
    for i := 0; i < 10; i++ {
        var s int
        s, a = a(i)
        fmt.Println(s)
    }
}

函数式编程入门

斐波那契数列

func fib() func() int {
    a, b := 1, 1
    return func() int {
        a, b = b, a+b
        return a
    }
}

f := fib()
for i := 0; i < 10; i++ {
    fmt.Println(f())
}
// 1 2 3 ... 55 89

这是用 print 打印的 fib 数,之前说道了 read 和 write 这两个基本接口.

现在让 fib这个函数实现一个 read 接口,然后任何能接收 reader 的方法都能输出这个 fib 数了

// 定义一个函数的结构体,用函数实现接口,函数和普通变量一样
type intGen func() int

func fib1() intGen {
    a, b := 1, 1
    return func() int {
        a, b = b, a+b
        return a
    }
}

把鼠标放到intGen 上,然后右键

go语言学习(11)--闭包与函数式编程

image

go语言学习(11)--闭包与函数式编程

image

go语言学习(11)--闭包与函数式编程

image

func (g intGen) Read(p []byte) (n int, err error) {
    // 下一个 fib 数
    next := g()
    //fib 数读不完,需要有一个结束条件
    if next > 1000 {
        return 0, io.EOF
    }
    // 底层找一个已经实现的
    s := fmt.Sprintf("%d\n", next)
    return strings.NewReader(s).Read(p)
}

注释已经写得很清楚了,让 intGen 这个函数结构体实现 reader 接口,等会就可以写一个 接收 reader 参数的print 函数,把intGen函数当做参数传进去了

/**
打印的方法
让 fib 实现 Reader 接口,就可以用 print 方法打印了
*/
func printFileContents(reader io.Reader) {
    scanner := bufio.NewScanner(reader)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
}

f1 := fib1()
printFileContents(f1)

// 1 2 3 5 8 13 21 34 ... 610 987

goimports

一个好用的工具

go语言学习(11)--闭包与函数式编程

image

能够自动整理imports

把没用到的去除,用到的,但系统没有的,自动 go get

但是正常是下不下来的,因为需要下载 golang.org/x/tools/cmd/goimports ,而 golang.org

在国内是被墙的

  1. go get -v github.com/gpmgo/gopm ,github 在国内没被墙,先下载 gopm 这个工具
  2. 配置 $ GOPATH:bin
  3. gopm get -v -g -u golang.org/x/tools/cmd/goimportsgopm 下载谷歌的 工具
  4. go install golang.org/x/tools/cmd/goimportsgoimports 安装到$ GOPATH 下

总结

scip

上述代码均已上传至 github, 欢迎 star

https://github.com/yejunyu/golearn
go语言学习(11)--闭包与函数式编程

image


以上所述就是小编给大家介绍的《go语言学习(11)--闭包与函数式编程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

深度探索C++对象模型

深度探索C++对象模型

斯坦利•B.李普曼 (Stanley B. Lippman) / 侯捷 / 电子工业出版社 / 2012-1 / 69.00元

作者Lippman参与设计了全世界第一套C++编译程序cfront,这本书就是一位伟大的C++编译程序设计者向你阐述他如何处理各种explicit(明确出现于C++程序代码中)和implicit(隐藏于程序代码背后)的C++语意。 本书专注于C++面向对象程序设计的底层机制,包括结构式语意、临时性对象的生成、封装、继承,以及虚拟——虚拟函数和虚拟继承。这本书让你知道:一旦你能够了解底层实现模......一起来看看 《深度探索C++对象模型》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

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

在线XML、JSON转换工具

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

正则表达式在线测试