[日常] 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"
}

  

posted @   唯一客服系统开发笔记  阅读(465)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· 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] 手机卫士手机定位的原理
点击右上角即可分享
微信分享提示
1
chat with us