[日常] Go语言圣经-匿名函数习题
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中的局部变量。
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | 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) } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2016-04-17 [javaEE] Servlet的调用过程和生命周期