[日常] Go语言圣经-错误,函数值习题
Go语言圣经-错误
1.panic异常。panic是来自被调函数的信号,表示发生了某个已知的bug
2.任何进行I/O操作的函数都会面临出现错误的可能
3.错误是软件包API和应用程序用户界面的一个重要组成部分,程序运行失败仅被认为是几个预期的结果之一
4.那些将运行失败看作是预期结果的函数,它们会返回一个额外的返回值,通常是最后一个,来传递错误信息
5.用户需要了解更多的错误信息。因此,额外的返回值不再是简单的布尔类型,而是error类型
6.内置的error是接口类型,error类型可能是nil或者non-nil
7.对于non-nil的error类型,我们可以通过调用error的Error函数或者输出函数获得字符串类型的错误信息。
8.少部分函数在发生错误时,仍然会返回一些有用的返回值。比如,读取文件
9.函数运行失败时会返回错误信息,这些错误信息被认为是一种预期的值
10.Go使用控制流机制(如if和return)处理异常,这使得编码人员能更多的关注错误处理
11.错误处理策略:传播错误,构造新的错误信息返回给调用者fmt.Errorf("parsing %s as HTML: %v", url,err)
12.第二种策略。如果错误的发生是偶然性的,或由不可预知的问题导致的。一个明智的选择是重新尝试失败的操作,限制重试的时间间隔或重试的次数,for循环 sleep
13.第三种策略:输出错误信息并结束程序,fmt.Fprintf(os.Stderr, "Site is down: %v\n", err)==log.Fatalf()
14.第四种策略:有时,我们只需要输出错误信息就足够了,不需要中断程序的运行,log.Printf()
15.io包保证任何由文件结束引起的读取失败都返回同一个错误——io.EOF
Go语言圣经-函数值
1.函数被看作第一类值(first-class values):函数像其他值一样,拥有类型,可以被赋值给其他变量,传递给函数,从函数返回。对函数值(function value)的调用类似函数调用
2.函数值使得我们不仅仅可以通过数据来参数化函数,亦可通过行为,strings.Map对字符串中的每个字符调用add1函数
3.利用fmt.Printf的一个小技巧控制输出的缩进。%*s中的*会在字符串之前填充一些空格
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 | package main import ( "fmt" "golang.org/x/net/html" "net/http" "os" "strings" ) func main() { outline(os.Args[1]) } func outline(url string) (string, error) { resp, err := http.Get(url) if err != nil { return "" , err } doc, _ := html.Parse(resp.Body) //1.使用函数值 //forEachNode(doc, startElement, endElement) //2. doc2 := ElementByID(doc, "navs" , startElement2) forEachNode(doc2, startElement, endElement) resp.Body.Close() s := expand( "footest" , expand2) fmt.Println(s) 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) } } var depth int /* 练习 5.7: 完善startElement和endElement函数,使其成为通用的HTML输出器。要求:输出注释结点,文本结点以及每个元素的属性(< a href='...'>)。使用简略格式输出没有孩子结点的元素(即用<img/>代替<img> </img>)。编写测试,验证程序输出的格式正确。(详见11章) 优化了script标签问题 */ func startElement(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) } } func endElement(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) } } /* 练习 5.8: 修改pre和post函数,使其返回布尔类型的返回值。返回false时,中止forEachNoded的遍历。使用修改后的代码编写ElementByID函数,根据用户输入的id查找第一个拥有该id元素的HTML元素,查找成功后,> 停止遍历。 func ElementByID(doc *html.Node, id string) *html.Node */ func ElementByID(n *html.Node, idStr string, pre func (*html.Node, string) bool) *html.Node { //显式的调用一下 if pre != nil { if pre(n, idStr) { return n } } //fmt.Println(n.Data) for c := n.FirstChild; c != nil; c = c.NextSibling { ElementByID(c, idStr, pre) } return n } func startElement2(n *html.Node, idStr string) bool { if n.Type == html.ElementNode { for _, a := range n.Attr { if a.Key == "id" && a.Val == idStr { fmt.Println(a.Val) break return true } } } return false } /* 练习 5.9: 编写函数expand,将s中的"foo"替换为f("foo")的返回值。 */ func expand(s string, f func (string) string) string { str := f( "foo" ) s = strings.Replace(s, "foo" , str, -1) return s } func expand2(s string) string { return s + "-test" } |
【推荐】国内首个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-16 [android] 手机卫士设备管理权限锁屏
2016-04-16 [android] 手机卫士手机实现短信指令获取位置
2016-04-16 [android] 手机卫士手机定位的原理