函数
函数值
函数可作为值被传递
go
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}函数闭包
- go函数可以是一个闭包。函数闭包可以作为变量绑定给变量,从语法上看类似于一种类型。每个被绑定的变量都拥有一个独立的函数闭包实例。
- 闭包是一个函数值,它引用了其函数体之外的变量。闭包并不会对捕获的变量进行拷贝后才使用,而是直接修改该变量本身。
go
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}go
package main
import "fmt"
func getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}
func main(){
/* nextNumber 为一个函数,函数 i 为 0 */
nextNumber := getSequence()
/* 调用 nextNumber 函数,i 变量自增 1 并返回 */
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
/* 创建新的函数 nextNumber1,并查看结果 */
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}闭包+goroutine
goroutine是go的轻量级线程,由 Golang 运行时进行管理。
有博主猜测终末地开服事件的根源是程序员踩进了goroutine+闭包的坑(当然最重要的还是他们没咋测试)。
go
package main
import (
"fmt"
"time"
)
func main() {
users := []string{"A", "B", "C"}
// =========================
// ❌ 错误写法(变量被闭包捕获)
// =========================
/*
for _, v := range users {
go func() {
// 闭包捕获的是变量 v 本身
// goroutine 可能在循环结束后才执行
// 此时 v 已经变成最后一个值
fmt.Println("wrong:", v)
}()
}
*/
// =========================
// ✅ 正确写法(参数传值)
// =========================
for _, v := range users {
go func(u string) { // 通过传参来立即拿到正确变量的副本,该副本是独立存储的,不会被原变量影响
// u 是当轮 v 的副本
// 每个 goroutine 拿到独立值
// goroutine 内的代码会延迟执行(本轮for循环大概率会在这里面的代码运行前结束)
fmt.Println("right:", u)
}(v)
}
time.Sleep(time.Second)
}