Go程序设计语言课后习题答案-第七章(接口)
第七章
- 接口即约定
- 接口类型
- 实现接口
- 使用flag.Value来解析参数
- 接口值
- 使用Sort.Interface来排序
- http.Handler接口
- error接口
- 示例: 表达式求值器
- 类型断言
- 使用类型断言来识别错误
- 通过接口类型断言来查询特性
- 类型分支
- 示例: 基于标记的XML解析
- 一些建议
这章是重点
练习7.1:
使用类似ByteCounter的想法,实现单词和行的计数器.实现时考虑使用bufio.ScanWords
- 创建一个结构体,实现Writer方法,分词得到写入的个数
1 | package main |
练习7.2:
实现一个满足如下前面的CountingWriter函数,输入一个io.Writer,输出一个封装了输入值的新Writer,以及一个指向int64的指针,该指针对应的值是新的Writer写入的字节数func CountingWriter(w io.Writer) (io.Writer, *int64)
- 这个地方使用了一个全局的变量统计写入的字节数,CountingWriter好像再外面封装了一层一样,仅仅只是为了记一个数,需要新建一个类型,然后让这个类型满足接口
1 | package main |
练习7.3:
为gopl.io/ch4/treesort中的*tree类型写一个String方法,用于展示其中的值序列
- 这个练习题比较直白了,估计是想说类型可以自己添加方法,这个地方直接使用广度优先保存下了列表然后打印一下
1 | func (t *tree) String() string { |
练习7.4:
strings.NewReader函数输入一个字符串,返回一个从字符串读取数据并满足io.Reader接口的值.请自己实现该函数,并且通过它来让HTML分析器支持以字符串作为输入
- Golang里面使用Newxxx这样的函数特别普遍,一个常用的套路,它初始化了一个struct,然后该结构体满足某接口
1 | package main |
练习7.5:
io包中的LimitReader函数接受io.Reader r和字节数n,返回一个Reader,该返回值从r读取数据,但在读取n字节后报告文件结束.请实现该函数func LimitReader(r io.Reader,n int64) io.Reader
- 感觉和上面的New差不多,只不过这个地方的初始化是使用了一个接口类型值
1 | package main |
练习7.6:
在tempflag中支持热力学温度
- 这题没什么意义,添加一个case判断就可以了
- 本小节主要讲解了flag.Value的原理,先有一个struct结构体,然后一个函数xxFlag(name string,value Type,usage string) *Type
- 上述函数调用flag.CommandLine.Var进行注册,当调用flag.Parse的时候调用结构体相应的Set方法,达到了解析命令行参数的目的
练习7.7:
请解释为什么默认值20.0没有写单位,而在帮助消息中却包含单位
- 接上一题,因为除了String方法还有Set方法,查看帮助的时候会调用它,在celsiusFlag结构体中String方法直接添加了单位
练习7.8:
很多图形界面提供了一个表格空间,它支持有状态的多层排序,先按照最近单击的列表排序,接着是上一次单击的列,依次类推.请定义sort.Interface接口来实现如上需求,试比较这个方法和多次使用sort.Stable排序的异同
- 这一节主要讲利用接口实现排序,需要排序的对象提供三个方法Len、Swap、Less
- 用一个slice来维持状态,Less函数使用倒序遍历加上switch开实现
- 对比sort.Stable来说,sort.Stable是稳定排序,一个对象有A/B两个属性,当使用稳定排序的时候假如A属性值相同,则对象相对位置不会改变
- 代码可能写的有点失败~~
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
99package main
import (
"time"
"fmt"
"sort"
)
type Track struct {
Title string
Artist string
Album string
Year int
Length time.Duration
}
var tracks = []*Track{
{"Go", "Delilah", "From the Roots Up", 2012, length("3m38s")},
{"Go", "Moby", "Moby", 1992, length("3m37s")},
{"Go Ahead", "Alicia Keys", "As I Am", 2007, length("4m36s")},
{"Ready 2 Go", "Martin Solveig", "Smash", 2011, length("4m24s")},
}
func length(s string) time.Duration {
d, err := time.ParseDuration(s)
if err != nil {
panic(s)
}
return d
}
type customSort struct {
t []*Track
r []string
}
var c = customSort{tracks,[]string{}}
func (x customSort) Len() int {
return len(x.t)
}
func (x customSort) Less(i, j int) bool {
for i := len(x.r) - 1; i >= 0; i-- {
switch x.r[i] {
case "Title":
if x.t[i].Title != x.t[j].Title {
return x.t[i].Title < x.t[j].Title
}
case "Artist":
if x.t[i].Artist != x.t[j].Artist {
return x.t[i].Artist < x.t[j].Artist
}
case "Album":
if x.t[i].Artist != x.t[j].Artist {
return x.t[i].Artist < x.t[j].Artist
}
case "Year":
if x.t[i].Year != x.t[j].Year {
return x.t[i].Year < x.t[j].Year
}
default:
panic("Not support field")
}
}
return false
}
func (x customSort) Swap(i, j int) {
x.t[i], x.t[j] = x.t[j], x.t[i]
}
func Sort(s string){
c.r = append(c.r,s)
if len(c.r) > 4{
c.r = c.r[:4]
}
sort.Sort(c)
}
func main() {
Sort("Title")
for _,v := range tracks{
fmt.Println(*v)
}
fmt.Println("=======")
Sort("Artist")
for _,v := range tracks{
fmt.Println(*v)
}
fmt.Println("=======")
Sort("Album")
for _,v := range tracks{
fmt.Println(*v)
}
}
练习7.9:
利用html/template包来替换printTracks函数,使用HTML表格来显示音乐列表,结合上一个练习,来实现通过单击列头来发送HTTP请求,进而对表格排序
- 对这题完全没兴趣,可以练习写template包
练习7.10:
sort.Interface也可以用于其他用户.试写一个函数IsPalindrome(s sort.Interface)bool来判断一个序列是否是回文,即序列反转后保持不变.可以假定对于下标分别为i、j的元素,如果!s.Less(i,j)&&!s.Less(j,i),那么两个元素相等
- 左右向中间比较,都相等则表示为回文,主要是用接口方法的Len和Less判断是否相等
1 | package main |
练习7.11:
增加额外的处理程序,来支持创建、读取、更新和删除数据库条目.比如,/update?item=socks&prince=6 这样的请求将更新仓库中物品的价格,如果商品不存在或者价格无效就返回错误
- 使用多个http.HandleFunc
- 使用锁防止并发修改
- 给struct添加多个方法就好了
1 | package main |
练习7.12:
修改/list的处理程序,改为输出HTML表格,而不是纯文本.可以考虑使用html/template包
- 这本书我已经数不清有多少个template包的练习了,老哥,这个模块是不是你写的!!!!!!
- restful当道的年代,没多少机会拼html啦
- 即使拼html,这也相当于在python里面不用Jinja这种模板引擎,而跑去用python自带的string.Template一样