(译)Go 语言中的闭包

原文链接:Special Memory Powers of Go Closures

通常 Go 语言中的命名函数只能在包级别定义,但是为了方便广大 Gopher,Go 语言允许 function literal 在任何表达式中表示一个函数。

那么 function literal 是什么呢?它就是没有名字的函数体。这些匿名函数与 JavaScript 领域内的函数是一样的。

  • (译)Go 语言中的闭包_第1张图片
    image.png

这些函数可以访问整个作用域,所以最内层的函数可以访问包裹它的函数中的变量。

  • (译)Go 语言中的闭包_第2张图片
    image.png

从截屏中可以看到 appendArray() 是一个返回值类型为 func() []int 的函数,一个 appendArray() 调用将创建一个本地变量 x 与 y 并返回匿名函数,每次执行它都将 x 加 1,然后将 x 追加到 slice y 中。第二个 appendArray() 调用创建了第二个本地变量 x 与 y ,它自增这个本地变量并且返回指定函数。

这与 Go 的预言正好相符:函数是引用类型,函数的值是不可以进行比较的

匿名函数是可以保存它们局部变量状态的,并且还可以访问或更改包裹它的函数的局部变量。

保存变量状态这个属性有助于我们解决很多计算机科学中的问题,例如:拓扑排序一下一个全栈开发工程师的技能树

//topological sort

package main

import (
    "fmt"
    "sort"
)

var pathOfFullstack = map[string][]string{
    "fullstack developer": {"C#", "Python", "Go", "Angular", "React"},
    "C#":      {"C"},
    "Angular": {"html", "Css", "Javascript"},
    "Go":      {"C#", "Python"},
    "React":   {"html", "Javascript", "JSX"},
}

func main() {
    for i, path := range topoSort(pathOfFullstack) {
        fmt.Printf("%d:\t%s\n", i+1, path)
    }
}

func topoSort(m map[string][]string) []string {
    var pathOrder []string
    visited := make(map[string]bool)
    var visitAll func(items []string)
    visitAll = func(items []string) {
        for _, item := range items {
            if !visited[item] {
                visited[item] = true
                visitAll(m[item])
                pathOrder = append(pathOrder, item)
            }
        }
    }
    var paths []string
    for devPath := range m {
        paths = append(paths, devPath)
    }
    sort.Strings(paths)
    visitAll(paths)
    return pathOrder
}

// Output 
/*
1:  html
2:  Css
3:  Javascript
4:  Angular
5:  C
6:  C#
7:  Python
8:  Go
9:  JSX
10: React
11: fullstack developer 
*/

所以下一次你定义 API,就可以施展一下你自己的 Go 语言闭包了。

你可能感兴趣的