[日常] Go语言圣经-匿名函数习题
程序员文章站
2022-04-15 16:50:08
Go语言圣经-匿名函数1.拥有函数名的函数只能在包级语法块中被声明,通过函数字面量(function literal),我们可绕过这一限制,在任何表达式中表示一个函数值2.通过这种方式定义的函数可以访问完整的词法环境(lexical environment),这意味着在函数中定义的内部函数可以引用该 ......
Go语言圣经-匿名函数
1.拥有函数名的函数只能在包级语法块中被声明,通过函数字面量(function literal),我们可绕过这一限制,在任何表达式中表示一个函数值
2.通过这种方式定义的函数可以访问完整的词法环境(lexical environment),这意味着在函数中定义的内部函数可以引用该函数的变量
3.函数值不仅仅是一串代码,还记录了状态,意味着匿名函数和父函数中,存在变量引用,函数值属于引用类型和函数值不可比较的原因。Go使用闭包(closures)技术实现函数值,Go程序员也把函数值叫做闭包
4.给定一些计算机课程,每个课程都有前置课程,只有完成了前置课程才可以开始当前课程的学习,这类问题被称作拓扑排序。从概念上说,前置条件可以构成有向图。
练习5.10: 重写topoSort函数,用map代替切片并移除对key的排序代码。验证结果的正确性(结果不唯一)。
练习5.11: 现在线性代数的老师把微积分设为了前置课程。完善topSort,使其能检测有向图中的环。
练习5.12: gopl.io/ch5/outline2(5.5节)的startElement和endElement共用了全局变量depth,将它们修改为匿名函数,使其共享outline中的局部变量。
package main import ( "fmt" "golang.org/x/net/html" "net/http" "sort" ) var prereqs = map[string][]string{ "algorithms": {"data structures"}, "calculus": {"linear algebra"}, "compilers": { "data structures", "formal languages", "computer organization", }, "data structures": {"discrete math"}, "databases": {"data structures"}, "discrete math": {"intro to programming"}, "formal languages": {"discrete math"}, "networks": {"operating systems"}, "operating systems": {"data structures", "computer organization"}, "programming languages": {"data structures", "computer organization"}, } func main() { for i, course := range topoSort(prereqs) { fmt.Printf("%d:\t%s\n", i+1, course) } fmt.Println("------------------------") for k, v := range topoSort2(prereqs) { fmt.Printf("%d:\t%s\n", k, v) } fmt.Println("------------------------") outline("http://mail.sina.net") } /* 练习5.10: 重写topoSort函数,用map代替切片并移除对key的排序代码。验证结果的正确性(结果不唯一)。 */ func topoSort2(m map[string][]string) map[int]string { var order = make(map[int]string) index := 1 seen := make(map[string]bool) var visitAll func(items []string) visitAll = func(items []string) { for _, item := range items { if !seen[item] { seen[item] = true visitAll(m[item]) order[index] = item index++ } } } var keys []string for key := range m { keys = append(keys, key) } visitAll(keys) return order } func topoSort(m map[string][]string) []string { var order []string seen := make(map[string]bool) var visitAll func(items []string) visitAll = func(items []string) { for _, item := range items { if !seen[item] { seen[item] = true visitAll(m[item]) order = append(order, item) } } } var keys []string for key := range m { keys = append(keys, key) } sort.Strings(keys) visitAll(keys) return order } /* 练习5.11: 现在线性代数的老师把微积分设为了前置课程。完善topSort,使其能检测有向图中的环。 等着去看数据结构再看这个题 */ /* 练习5.12: gopl.io/ch5/outline2(5.5节)的startElement和endElement共用了全局变量depth,将它们修改为匿名函数,使其共享outline中的局部变量。 */ func outline(url string) (string, error) { resp, err := http.Get(url) if err != nil { return "", err } doc, _ := html.Parse(resp.Body) //使用匿名函数实现 var depth int var startElement func(n *html.Node) var endElement func(n *html.Node) startElement = func(n *html.Node) { if n.Type == html.ElementNode { attr := "" for _, a := range n.Attr { attr += " " + a.Key + "=" + "\"" + a.Val + "\" " } fmt.Printf("%*s<%s%s", depth*2, "", n.Data, attr) depth++ } if n.Type == html.ElementNode && n.FirstChild == nil && n.Data != "script" { fmt.Printf("/>\n") } else if n.Type == html.ElementNode { fmt.Printf(">\n") } if n.Type == html.TextNode { fmt.Printf("%*s %s\n", depth*2, "", n.Data) } } endElement = func(n *html.Node) { if n.Type == html.ElementNode && n.FirstChild == nil && n.Data != "script" { depth-- fmt.Printf("\n") return } if n.Type == html.ElementNode { depth-- fmt.Printf("%*s</%s>\n", depth*2, "", n.Data) } } //1.使用函数值 forEachNode(doc, startElement, endElement) resp.Body.Close() return "", nil } func forEachNode(n *html.Node, pre, post func(n *html.Node)) { //显式的调用一下 if pre != nil { pre(n) } //fmt.Println(n.Data) for c := n.FirstChild; c != nil; c = c.NextSibling { forEachNode(c, pre, post) } if post != nil { post(n) } }