0x00 函数与闭包
函数是一等公民:即参数,变量,返回值都可以是函数
"正统的"函数式编程:
不可变性:不能有变量,只有常量和函数
函数只能有一个参数
因为go语言是一个通用的语言,所以不完全按照”正统“的函数式编程进行
闭包的底层原理:
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(v int) int {
sum += v
return sum
}
}
func main() {
a := adder()
for i := 0; i < 10; i++ {
fmt.Printf("0+1+...+%d=%d\n", i, a(i))
}
}
执行结果:
因为函数adder返回的函数中调用了”自由变量“sum, 所以adder 函数返回的并不只是函数地址,而是
首先会在内存的堆中存储这些自由变量,然后在堆中创建一个结构体,把这些变量的地址和函数的地址打个包存起来
最后,将该结构体在堆中的地址打包返回。
正因如此,我们在执行反复执行a() 的时候 sum的值会累加。
更加详细的解释:https://zhuanlan.zhihu.com/p/56750616
0x01 闭包的应用
1.斐波那契数列:
package main
import "fmt"
func fibanacci() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
func main() {
f := fibanacci()
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
fmt.Println(f())
}
2.逐行读取文件 之 再深入
通过阅读源码我的总结如下:
func printFile(filename string) {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
//file 具有一个Read方法 NewScanner 的作用其实就是将 file 和 其他相关信息 封装到一个 scanner结构体中,然后把该结构体的地址返回
scanner := bufio.NewScanner(file)
//scanner.Scan() 这个方法其实是在调用 file.Read() 方法
for scanner.Scan() {
fmt.Println(scanner.Text()) //scanner.Text() 方法只有一行代码,并不执行读相关的操作,只是将scanner.Scan()读到的信息转化为字符串
}
}
func forever() {
for {
fmt.Println("forever")
}
}
因为io.Reader就是一个鸭子类型,所以我们完全可以自己写一个 io.Reader类型的东西 给NewScanner传进去
/*
* @Author: your name
* @Date: 2020-11-03 22:02:35
* @LastEditTime: 2020-11-03 23:55:52
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: /learngo/functional/fibanacc/fibanacci.go
*/
package main
import (
"bufio"
"fmt"
"io"
"strings"
)
type intGen func() int
func fibanacci() intGen {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
//因为函数是一等公民,
//给这个函数添加一个成员函数 Read ,
//让它符合 io.Reader 这个interface的要求
func (g intGen) Read(p []byte) (n int, err error) {
next := g()
if next > 10000 {
return 0, io.EOF
}
s := fmt.Sprintf("%d\n", next)
reader := strings.NewReader(s) //创建一个从s读取数据的reader
return reader.Read(p) //从s读取数据存到p中,返回读取到的字符串的长度
}
//io.Reader io包中定义的一个鸭子类型,要求必须有成员函数Read
func printFileContents(reader io.Reader) {
scanner := bufio.NewScanner(reader) //返回一个Scanner
//sanner.Scan()本质上在反复调用 reader.Read()
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
func main() {
f := fibanacci()
printFileContents(f)
}