[日常] 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中的局部变量。
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)
}
}
[日常] Go语言圣经-匿名函数习题的更多相关文章
- [日常] Go语言圣经-匿名函数习题2
练习5.13: 修改crawl,使其能保存发现的页面,必要时,可以创建目录来保存这些页面.只保存来自原始域名下的页面.假设初始页面在golang.org下,就不 要保存vimeo.com下的页面. p ...
- [日常] Go语言圣经-错误,函数值习题
Go语言圣经-错误 1.panic异常.panic是来自被调函数的信号,表示发生了某个已知的bug 2.任何进行I/O操作的函数都会面临出现错误的可能 3.错误是软件包API和应用程序用户界面的一个重 ...
- [日常] Go语言圣经--接口约定习题
Go语言圣经-接口1.接口类型是对其它类型行为的抽象和概括2.Go语言中接口类型的独特之处在于它是满足隐式实现的3.Go语言中还存在着另外一种类型:接口类型.接口类型是一种抽象的类型4.一个类型可以自 ...
- [日常] Go语言圣经-Deferred函数
1.只需要在调用普通函数或方法前加上关键字defer,就完成了defer所需要的语法.当defer语句被执行时,跟在defer后面的函数会被延迟执行.直到包含该defer语句的函数执行完毕时,defe ...
- [日常] Go语言圣经-竞争条件习题
package main import( "fmt" "sync" ) var balance int func Deposit(amount int) { b ...
- [日常] Go语言圣经-可变参数习题
1.参数数量可变的函数称为为可变参数函数,例子就是fmt.Printf和类似函数2.参数列表的最后一个参数类型之前加上省略符号“...”3.虽然在可变参数函数内部,...int 型参数的行为看起来很像 ...
- [日常] Go语言圣经-Slice切片习题
1.Slice(切片)代表变长的序列,序列中每个元素都有相同的类型,一个slice类型一般写作[]T,其中T代表slice中元素的类型:slice的语法和数组很像,只是没有固定长度而已,slice的底 ...
- [日常] Go语言圣经--接口约定习题2
练习 7.3: 为在gopl.io/ch4/treesort (§4.4)的*tree类型实现一个String方法去展示tree类型的值序列. package main import( "f ...
- [日常] Go语言圣经-函数多返回值习题
Go语言圣经-函数多返回值1.在Go中,一个函数可以返回多个值2.许多标准库中的函数返回2个值,一个是期望得到的返回值,另一个是函数出错时的错误信息3.如果一个函数将所有的返回值都显示的变量名,那么该 ...
随机推荐
- Centos 7 安装 PostgreSQL PGAdmin4
本文只讲PostgreSQL在CentOS 7.x 下的安装,其他系统请查看:https://www.postgresql.org/download PostgreSQL 所用版本为:PostgreS ...
- Git之初识
我的Github地址:https://github.com/shinianzongjishinianxin 初见总是美好的,可是我第一次看到github有点纠结,因为看不懂,然而最终半蒙半猜还是注册完 ...
- WinRAR试用过期决绝方法
一.WinRAR 试用过期决绝方法 直接去WINRAR官方下个版本装上然后这样 复制以下内容(红色)到记事本,保存为rarreg.key文件(即文件名是rarreg,扩展名是key),把这文件拷贝到W ...
- 获取用户真实ip
public static string GetRealIP() { string result = System.Web.HttpContext.Current.Request.Headers[&q ...
- 背水一战 Windows 10 (43) - C# 7.0 新特性
[源码下载] 背水一战 Windows 10 (43) - C# 7.0 新特性 作者:webabcd 介绍背水一战 Windows 10 之 C# 7.0 新特性 介绍 C# 7.0 的新特性 示例 ...
- 背水一战 Windows 10 (46) - 控件(ScrollViewer 基础): ScrollViewer, ScrollBar, ScrollContentPresenter
[源码下载] 背水一战 Windows 10 (46) - 控件(ScrollViewer 基础): ScrollViewer, ScrollBar, ScrollContentPresenter 作 ...
- 关于IE9 table显示错位的问题
首先,win10无法安装IE9,所以需要用IE11模拟IE9,这样:http://www.w10zj.com/Win10xy/Win10yh_638.html: 其次,table显示错位的可能原因:h ...
- Linux正则与文本处理工具(10)
正则表达式 (Regular Expression, RE, 或称为常规表达式)是通过一些特殊字符的排列,用于『查找/替换/删除』一行或多行文字或字符串,简单的说,正则表达式就是用在字串的处理上面的一 ...
- mybatis-spring集成:配置多数据库源中遇到的问题
转自:http://www.cfanz.cn/index.php?c=article&a=read&id=71583 mybatis配置多数据源本身很简单,和基本配置差别不大 但是如果 ...
- Spring Boot中使用@Scheduled创建定时任务
我们在编写Spring Boot应用中经常会遇到这样的场景,比如:我需要定时地发送一些短信.邮件之类的操作,也可能会定时地检查和监控一些标志.参数等. 创建定时任务 在Spring Boot中编写定时 ...