前端开发者的GO语言之路(5) —— 函数式编程

1. 函数式编程

1.1 使用闭包

使用函数式编程思想,我们可以在一个函数中返回一个函数,构造一个累加器如下:

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.Println(a(i))
	}
}

如上的Go语言函数式编程与Javascript的闭包机制很像,如果上面的累加器使用Javascript写,如下我们能很容易看出相似之处:

function adder() {
  let sum = 0
  return function (i) {
    sum += i;
    return sum
  }
}

let a = adder()

for (let i = 0; i < 10; i++) {
  console.log(a(i))
}

1.2 正统函数式编程写法

严格的函数式编程需要满足如下条件:

  • 不可变性:不能有状态,只有常量和函数
  • 函数只能有一个参数

由于正统的函数式编程要求严格,代码可读性会较差

type iAdder func(int) (int, iAdder)

func adder2(base int) iAdder {
	return func(v int) (int, iAdder) {
		return base + v, adder2(base + v)
	}
}
func main() {
	a2 := adder2(0)
	for i := 0; i < 10; i++ {
		var s int
		s, a2 = a2(i)
		fmt.Println(s)
	}
}

1.3 使用函数遍历二叉树

常规方式遍历二叉树的方式如下:

// 先序遍历
func (node *Node) Traverse() {
	if node == nil {
		return
	}
	node.Print()
	node.Left.Traverse()
	node.Right.Traverse()
}

这个方式有一个很明显的缺点,就是我们在调用 Traverse() 方法时,只能按照方法内部编写的方式去操作遍历二叉树,即只能打印出二叉树的每个节点,如果我们想要去增加遍历每个节点时的操作,就需要重新改写 Traverse() 方法。

那么如果使用编程式函数的思想,将函数作为一个参数传入方法中,在这个方法中调用该函数,那么我们只需要修改调用方法时传入的函数,就可以拓展功能,所以我们可以将上面的方法改写为:

func (node *Node) TraverseFunc(f func(*Node)) {
	if node == nil {
		return
	}
	f(node)
	node.Left.TraverseFunc(f)
	node.Right.TraverseFunc(f)
}

在调用时可以将任意函数传入,TraverseFunc() 方法内:

node.TraverseFunc(func(node *Node) {
    // 添加用户自定义的操作,这些操作将会在遍历过程中执行,用户可以对其随意拓展
    node.Print()
})

这种方式与javascript的callback回调函数思想相似,都是向A函数传入B函数,在A函数的某一固定位置执行B函数。

  • go语言的闭包不需要修饰
  • 没有Lambda表达式,但是有匿名函数
发布了48 篇原创文章 · 获赞 28 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/u012925833/article/details/100902903