函数:请叫我“一等公民”
函数是唯一一种基于特定输入,实现特定任务并可返回任务执行结果的代码块
Go 程序就是一组函数的集合
Go 函数与函数声明
函数的出现也提升了整个程序界代码复用的水平
特征一:Go 函数可以存储在变量中。
var (
myFprintf = func(w io.Writer, format string, a ...interface{}) (int, error) {
return fmt.Fprintf(w, format, a...)
}
)
func main() {
fmt.Printf("%T\n", myFprintf) // func(io.Writer, string, ...interface {}) (int, error)
myFprintf(os.Stdout, "%s\n", "Hello, Go") // 输出Hello,Go
}
特征二:支持在函数内创建并通过返回值返回。
func setup(task string) func() {
println("do some setup stuff for", task)
return func() {
println("do some teardown stuff for", task)
}
}
func main() {
teardown := setup("demo")
defer teardown()
println("do some bussiness stuff")
}
特征三:作为参数传入函数。
time.AfterFunc(time.Second*2, func() { println("timer fired") })
特征四:拥有自己的类型。
// $GOROOT/src/net/http/server.go
type HandlerFunc func(ResponseWriter, *Request)
// $GOROOT/src/sort/genzfunc.go
type visitFunc func(ast.Node) ast.Visitor
函数“一等公民”特性的高效运用
应用一:函数类型的妙用
func greeting(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Welcome, Gopher!\n")
}
func main() {
http.ListenAndServe(":8080", http.HandlerFunc(greeting))
}
// $GOROOT/src/net/http/server.go
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r)}
这里的 (f HandlerFunc) 写在函数名ServeHTTP 前面,
- “这里的 (f HandlerFunc) 写在函数名ServeHTTP 前面” 说明ServeHTTP是HanderFunc类型的一个方法
type MyInt int
var x int = 5
y := MyInt(x)
// MyInt的底层类型为int,类比HandlerFunc的底层类型为func(ResponseWriter, *Request)
应用二:利用闭包简化函数调用。
func times(x, y int) int {
return x * y
}
func partialTimes(x int) func(int) int {
return func(y int) int {
return times(x, y)
}
}
func main() {
timesTwo := partialTimes(2) // 以高频乘数2为固定乘数的乘法函数
timesThree := partialTimes(3) // 以高频乘数3为固定乘数的乘法函数
timesFour := partialTimes(4) // 以高频乘数4为固定乘数的乘法函数
timesTwo = func(y int) int {
return times(2, y)
}
fmt.Println(timesTwo(5)) // 10,等价于times(2, 5)
fmt.Println(timesTwo(6)) // 12,等价于times(2, 6)
fmt.Println(timesThree(5)) // 15,等价于times(3, 5)
fmt.Println(timesThree(6)) // 18,等价于times(3, 6)
fmt.Println(timesFour(5)) // 20,等价于times(4, 5)
fmt.Println(timesFour(6)) // 24,等价于times(4, 6)
}