函数是一等公民,函数类型是一等的数据类型。
函数值是能被随意传播的独立逻辑组件。
package main
import (
"fmt"
)
// 函数声明,名叫 Printer
// 参数:contents string
// 返回的结果列表:n int, err error
type Printer func(contents string) (n int, err error)
// 函数实现
func printToStd(contents string) (butesNum int, err error) {
return fmt.Println(contents)
}
func main(){
var p Printer
p = printToStd // 将函数作为一个普通值赋给变量
p("something")
}
高阶函数
想通过编写 calculate 函数实现两个整数间的加减乘除运算,但希望两个整数和具体的操作由函数的调用方给出。
方案一:
package main
import (
"fmt"
"errors"
)
type operate func(x, y int) int
// 将函数作为参数传递
func calculate(x int, y int, op operate) (int, error) {
if op == nil {
return 0, errors.New("invalid operation")
}
return op(x, y), nil
}
func main(){
x, y := 12, 23
op := func(x, y int) int {
return x + y
}
result, err := calculate(x, y, op)
fmt.Printf("The result: %d (error: %v)\n", result, err)
result, err = calculate(x, y, nil)
fmt.Printf("The result: %d (error: %v)\n", result, err)
}
方案二:
package main
import (
"fmt"
"errors"
)
type operate func(x, y int) int
type calculateFunc func(x int, y int) (int, error)
// 将其它的函数作为结果返回
// 闭包:在一个函数中存在对外来标识符的引用
// genCalculator 内定义了一个匿名函数
// 该匿名函数为闭包函数,op 既不代表它的任何参数或结果,也不是它自己声明的,而是一个自由变量
// op 这个自由变量代表什么,不是在定义闭包函数时确定的,而是在 genCalculator 被调用时确定的
func genCalculator(op operate) calculateFunc {
return func(x int, y int) (int, error) {
if op == nil {
return 0, errors.New("invalid operation")
}
return op(x, y), nil
}
}
func main(){
x, y := 12, 23
op := func(x, y int) int {
return x + y
}
add := genCalculator(op)
result, err := add(x, y)
fmt.Printf("The result: %d (error: %v)\n", result, err)
}
参数传递
package main
import (
"fmt"
)
func main(){
// 参数为值类型:数组
array1 := [3]string{"a", "b", "c"}
fmt.Printf("The array: %v\n", array1)
array2 := modifyArray(array1)
fmt.Printf("The modified array: %v\n", array2)
fmt.Printf("The original array: %v\n", array1)
fmt.Println()
// 参数为引用类型:切片、字典、通道
slice1 := []string{"x", "y", "z"}
fmt.Printf("The slice: %v\n", slice1)
slice2 := modifySlice(slice1)
fmt.Printf("The modified slice: %v\n", slice2)
fmt.Printf("The original slice: %v\n", slice1)
fmt.Println()
// complexArray1 是一个数组,但其中的每个元素是一个切片
// 改变一维,不会影响原值
// 改变二维,会影响原值
complexArray1 := [3][]string{
[]string{"d", "e", "f"},
[]string{"g", "h", "i"},
[]string{"j", "k", "l"},
}
fmt.Printf("The complex array: %v\n", complexArray1)
complexArray2 := modifyComplexArray(complexArray1)
fmt.Printf("The modifed complex array: %v\n", complexArray2)
fmt.Printf("The original complex array: %v\n", complexArray1)
}
func modifyArray(a [3]string) [3]string {
a[1] = "x"
return a
}
func modifySlice(a []string) []string {
a[1] = "i"
return a
}
func modifyComplexArray(a [3][]string) [3][]string {
a[1][1] = "s"
a[2] = []string{"o", "p", "q"}
return a
}