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一样

 官方网站:
 官方网站: