golang 闭包

golang 匿名函数&闭包

匿名函数

定义: 匿名函数是一种没有名称的函数,可以在声明的同时被调用或赋值给变量。

用处:

  • 实现简单的一次性使用的功能,无需定义具名函数。
  • 作为高阶函数的参数,例如在sort.Slice()中定义排序规则。
  • 在goroutine中快速定义并发任务。
  • 实现延迟执行的逻辑,如defer语句。

示例:

a. 作为函数参数 (用于回调):

1
2
3
4
5
6
7
8
9
func executeAndPrint(f func() string) {
    fmt.Println(f())
}

func main() {
    executeAndPrint(func() string {
        return "Hello from anonymous function!"
    })
}

b. 在 goroutine 中使用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func main() {
    go func() {
        for i := 0; i < 5; i++ {
            fmt.Printf("Goroutine: %d\n", i)
            time.Sleep(100 * time.Millisecond)
        }
    }()

    time.Sleep(1 * time.Second)
}

c. 实现简单的装饰器模式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func timeTrack(f func()) func() {
    return func() {
        start := time.Now()
        f()
        fmt.Printf("Function took %v\n", time.Since(start))
    }
}

func main() {
    slowFunc := func() {
        time.Sleep(100 * time.Millisecond)
        fmt.Println("Slow function finished")
    }

    timedSlowFunc := timeTrack(slowFunc)
    timedSlowFunc()
}

闭包

定义: 闭包是一个函数值,它引用了其外部作用域的变量。闭包通常通过在函数内部定义并返回另一个函数来创建。

用处:

  • 实现数据封装和信息隐藏。
  • 创建函数工厂,生成定制化的函数。
  • 实现记忆化,缓存函数的结果。
  • 在并发编程中共享状态。

示例: a. 实现计数器:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func createCounter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    counter := createCounter()
    fmt.Println(counter()) // 1
    fmt.Println(counter()) // 2
    fmt.Println(counter()) // 3
}

b. 实现配置函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
type Server struct {
    host string
    port int
}

func NewServer(host string, port int) *Server {
    return &Server{host, port}
}

func (s *Server) WithHost(host string) func(*Server) {
    return func(s *Server) {
        s.host = host
    }
}

func (s *Server) WithPort(port int) func(*Server) {
    return func(s *Server) {
        s.port = port
    }
}

func main() {
    server := NewServer("localhost", 8080)
    server.WithHost("example.com")(server)
    server.WithPort(9000)(server)
    fmt.Printf("Server: %+v\n", server)
}

c. 实现中间件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        fmt.Printf("Request to %s took %v\n", r.URL.Path, time.Since(start))
    }
}

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}

func main() {
    http.HandleFunc("/", loggingMiddleware(hello))
    http.ListenAndServe(":8080", nil)
}

d. 实现记忆化 (缓存函数结果):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func memoize(f func(int) int) func(int) int {
    cache := make(map[int]int)
    return func(x int) int {
        if val, found := cache[x]; found {
            return val
        }
        result := f(x)
        cache[x] = result
        return result
    }
}

func fibonacci(n int) int {
    if n <= 1 {
        return n
    }
    return fibonacci(n-1) + fibonacci(n-2)
}

func main() {
    memoFib := memoize(fibonacci)
    fmt.Println(memoFib(40)) // 快速计算,结果被缓存
    fmt.Println(memoFib(40)) // 直接从缓存中获取结果
}

e. 实现延迟执行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func delayExecution(f func()) func() {
    var once sync.Once
    return func() {
        once.Do(f)
    }
}

func main() {
    heavyTask := func() {
        fmt.Println("Executing heavy task...")
        time.Sleep(2 * time.Second)
        fmt.Println("Heavy task completed.")
    }

    delayedTask := delayExecution(heavyTask)

    // 第一次调用会执行任务
    delayedTask()

    // 后续调用不会重复执行
    delayedTask()
    delayedTask()
}

References

Licensed under CC BY-NC-SA 4.0