爱上开源之golang入门至实战第四章函数(Func)(七)
4.4.7 函数作为参数
在go语言里,func本质上是一个类型关键字。 使用func来进行声明,本质上就是什么了一个func的对象。 对象名为function_name, 这个对象的类型是func。 所以在golang语言里, 在访问范围的允许情况下, 函数可以作为一个对象进行访问或者赋值给另外一个变量; 或者函数也可以作为其它函数的参数进行传递,然后在其它函数内调用执行; 就和Javascript里的callback函数一样;这个文章就来谈谈,函数作为参数在Go语言里的调用。
先来看看一个例子:
func PrintFibonacci(n int, fibonacciWorker func(num int) []int) {
if fibonacciWorker == nil {
panic("Not assign worker")
}
result := fibonacciWorker(n)
fmt.Printf("Fibonacci(%d)=%v \n", n, result)
}
func FibonacciWorker(a int) (n []int) {
if a <= 0 {
n = append(n, 0)
return
}
if a == 1 {
n = append(FibonacciC(a-1), 1)
return
}
n = append(FibonacciC(a - 1))
n = append(n, n[len(n)-1]+n[len(n)-2])
return
}
PrintFibonacci(4, FibonacciWorker)
PrintFibonacci(6, FibonacciWorker)
PrintFibonacci(10, FibonacciWorker)
===== OUTPUT =====
Fibonacci(4)=[0 1 1 2 3]
Fibonacci(6)=[0 1 1 2 3 5 8]
Fibonacci(10)=[0 1 1 2 3 5 8 13 21 34 55]
上述代码,
首先定义了PrintFibonacci函数,PrintFibonacci函数两个参数,
第一个参数是整数类型,传入调用的n值,
另一个参数fibonacciWorker是一个函数类型的参数;函数类型的参数是整数型类型,用来接收传入参数,返回一个整数类型的数组,
在PrintFibonacci函数里, 把接收到的整数类型n,作为参数传递到fibonacciWorker这个传入的函数类型,并执行fibonacciWorker函数,返回整数型类型的数组,
然后把返回值打印到控制台; 这样的Callback的实现模式,
可以实现一些Java设计模式里的效果。 把具体的实现实现在具体函数里, 定义好这种函数类型的传入参数,返回值,
然后把此类函数类型作为参数传入, 在外部调用时, 把具体的实现作为参数对这个方法进行调用,就可以达到实现和接口的隔离了。 函数也可以作为数组的元素, 把数组里的元素遍历再进行调用。
来看看下面的代码:
type WordProcess func(input string) string
func filter(source string, chains []WordProcess) string {
for _, process := range chains {
if process != nil {
fmt.Printf("%q =>", source)
source = process(source)
fmt.Printf("%q\n", source)
}
}
return source
}
定义了一个WordProcess的函数类型, 传入参数字符串,返回字符串; WordProcess对传入的字符串进行字符处理。
在第二段,定义一个filter函数,函数传入source字符串,和一个WordProcess的函数数组; 函数数组都是进行字符处理的,遍历数组取到每个WordProcess函数,并依次进行处理,然后打印转换的过程,并返回结果。
下面我们来看看调用的代码
func main() {
toUpper := func(input string) string {
return strings.ToUpper(input)
}
toTrim := func(input string) string {
return strings.TrimSpace(input)
}
toTrimPrefix := func(input string) string {
return strings.TrimPrefix(input, "AAA")
}
chains := append([]WordProcess(nil), toUpper, toTrim, toTrimPrefix)
result := filter(" aaa hello ", chains)
fmt.Printf("result = %v \n", result)
}
===== OUTPUT =====
" aaa hello " =>" AAA HELLO "
" AAA HELLO " =>"AAA HELLO"
"AAA HELLO" =>" HELLO"
result = HELLO
这个调用段的过程;
先定义一个WordProcess的函数实现toUpper, 该实现对传入字符串进行转大写处理; 接着定义一个toTrim的函数,该函数实现对传入字符串进行去除空格处理, 最后定义一个toTrimPrefix的函数,将传入字符串前AAA字符串进行出除。
然后通过Append函数,将三个预先定义好的WordProcess函数对象加入到chains数组里,
最后传入字符串" aaa hello "进行filter调用, 通过filter依次调用,最后的结果就是HELLO了。
结束语
通过这样的方式,可以实现一些设计模式,特别是应用系统设计里,经常就有类似的代码可以发现。http里提供路由的功能就是使用类似以上的代码进行实现的。