参考地址
- https://hedzr.com/golang/fp/golang-functional-programming-in-brief/
- https://silverrainz.me/blog/funtional-programming-in-go-generics.html
- https://zhuanlan.zhihu.com/p/436468481
函数式编程(Functional Programming / FP)作为一种编程范式,具有无状态、无副作用、并发友好、抽象程度高等优点。
Go语言并不是一门纯粹的函数式编程语言,但它支持一些函数式编程的特性和思想。函数式编程是一种编程范式,
其核心理念是将计算视为函数应用的组合,强调使用纯函数、不可变性和避免副作用。
声明式编程:函数式编程倾向于使用声明式风格,将关注点放在"做什么"而不是"如何做"上。通过使用函数组合、管道操作符等,可以在Go中实现声明式的风格,使代码更易读、简洁和可维护。
- 高阶函数:Go语言中函数是一等公民,可以作为参数传递给其他函数,也可以作为返回值。这使得我们可以编写高阶函数,即接受其他函数作为参数或返回函数的函数。
- 闭包:Go语言支持闭包,可以在函数内部定义函数,并访问外部函数的变量。闭包在函数式编程中常用于创建不可变的函数,或者捕获一些状态并将其封装在函数中。
- 函数组合:通过将多个函数组合在一起形成新的函数,可以实现函数的复用和组合。可以使用函数的嵌套调用、函数参数传递和返回函数等方式来实现函数组合。
- 纯函数:纯函数是指没有副作用的函数,即函数的返回值仅由输入决定,不依赖于外部状态。在Go中,可以通过避免修改函数外部的变量和数据,以及避免使用全局状态,来编写纯函数。
- 不可变性:尽量避免在函数中修改传入的参数或外部变量,而是创建新的数据结构或使用函数返回新的结果。这样可以减少副作用,增加代码的可读性和可维护性。
- 函数链式调用:通过返回对象本身或其他具有相同方法的对象,可以实现函数链式调用的风格。这在Go中常用于构建流畅的API接口或操作符。
高阶函数示例:
定义一个高阶函数mapInts,它接受一个整数切片和一个函数作为参数,并将该函数应用于切片中的每个元素。
func mapInts(nums []int, f func(int) int) []int {
result := make([]int, len(nums))
for i, num := range nums {
result[i] = f(num)
}
return result
}
func main() {
nums := []int{1, 2, 3, 4, 5}
doubled := mapInts(nums, func(x int) int {
return x * 2
})
fmt.Println(doubled) // Output: [2 4 6 8 10]
}
闭包示例:
使用闭包创建一个计数器函数,每次调用计数器函数都会增加计数器的值。
func newCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
counter := newCounter()
fmt.Println(counter()) // Output: 1
fmt.Println(counter()) // Output: 2
fmt.Println(counter()) // Output: 3
}
函数组合示例:
定义两个函数addOne和double,然后将它们组合在一起形成一个新的函数addOneAndDouble。
func addOne(x int) int {
return x + 1
}
func double(x int) int {
return x * 2
}
func compose(f func(int) int, g func(int) int) func(int) int {
return func(x int) int {
return f(g(x))
}
}
func main() {
addOneAndDouble := compose(addOne, double)
result := addOneAndDouble(2)
fmt.Println(result) // Output: 5
}
斐波那契数列
想要直接调用 printContentFile () 自动生成斐波那契数,就必须实现 read 接口,定义一个 type:函数。使其实现 Reader 接口。
//函数实现接口
//定义一个函数,使用type修饰。可以实现接口,也就是说只要是被type修饰的东西都可以实现接口。
type IntGen func() int
//实现read接口
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)
return strings.NewReader(s).Read(p)
}
func printContentFile(reader io.Reader) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() { //
println(scanner.Text())
}
}
func fibonacci() IntGen {
a := 0
b := 1
return func() int {
a, b = b, a+b
return a
}
}
func main(){
fun := fibonacci()
printContentFile(fun)
}