7.1:使用类似ByteCounter的想法,实现单词和行的计数器,实现时考虑使用bufio.ScanWords。
package main import ( "bufio" "fmt" ) type WordsCounter int func (c *WordsCounter) Write(content []byte) (int, error) { for start := 0; start < len(content); { //跳过开头的space,返回遇到第一个word后下次scan的开始index //Hello Worlds 调用bufio.ScanWords返回 //6 [Hello的字节slice] nil advance, _, err := bufio.ScanWords(content[start:], true) if err != nil { return 0, err } start += advance (*c)++ } return int(*c), nil } type LinesCounter int func (c *LinesCounter) Write(content []byte) (int, error) { for start := 0; start < len(content); { advance, _, err := bufio.ScanLines(content[start:], true) if err != nil { return 0, err } start += advance (*c)++ } return int(*c), nil } func main() { var wc WordsCounter wc.Write([]byte("Hello Worlds Test Me")) fmt.Println(wc) // 4 wc.Write([]byte("append something to the end")) fmt.Println(wc) // 9 var lc LinesCounter fmt.Fprintf(&lc, "%s\n%s\n%s\n", "Hello World", "Second Line", "Third Line") fmt.Println(lc) // 3 fmt.Fprintf(&lc, "%s\n%s\n%s", "第4行", "第5行", "") fmt.Println(lc) // 5 }
7.2:实现一个满足如下签名的CountingWriter函数,输入一个io.Writer,输出一个封装了输入值的心Writer,以及一个置项int64的指针,改制真对应的值是新的Writer吸入的字节数。
package main import ( "fmt" "io" "os" ) type CountWriter struct { Writer io.Writer Count int } func (cw *CountWriter) Write(content []byte) (int, error) { n, err := cw.Writer.Write(content) if err != nil { return n, err } cw.Count += n return n, nil } func CountingWriter(writer io.Writer) (io.Writer, *int) { cw := CountWriter{ Writer: writer, } return &cw, &(cw.Count) } func main() { cw, counter := CountingWriter(os.Stdout) fmt.Fprintf(cw, "%s", "Print somethind to the screen...") fmt.Println(*counter) cw.Write([]byte("Append soething...")) fmt.Println(*counter) }
7.3:为gopl.io/ch4/treesort中的*tree类型写一个String方法,用于展示其中的值序列。
package main import ( "fmt" "math/rand" ) type tree struct { value int left, right *tree } func (t *tree) String() string { res := "" if t == nil { return res } res += t.left.String() res = fmt.Sprintf("%s %d", res, t.value) res += t.right.String() return res } func buildTree(data []int) *tree { var root = new(tree) for _, v := range data { root = add(root, v) } return root } func add(t *tree, e int) *tree { if t == nil { t = new(tree) t.value = e return t } if e < t.value { t.left = add(t.left, e) } else { t.right = add(t.right, e) } return t } func main() { data := make([]int, 50) for i := range data { data[i] = rand.Int() % 50 } root := buildTree(data) fmt.Println(root) //空指针 fmt.Println(new(tree)) //只有根节点 root = new(tree) root.value = 100 fmt.Println(root) //没有右子树 data = []int{5, 4, 3, 2, 1} root = buildTree(data) fmt.Println(root) //没有左子树 data = []int{1, 3, 2, 4, 5} root = buildTree(data) fmt.Println(root) }
7.4:strings.NewReader函数输入一个字符串,返回一个从字符串读取数据并满足io.Reader接口的值。请实现该函数。
package main import ( "fmt" "io" ) type StringReader struct { data string n int } func (sr *StringReader) Read(b []byte) (int, error) { data := []byte(sr.data) if sr.n >= len(data) { return 0, io.EOF } data = data[sr.n:] n := 0 if len(b) >= len(data) { n = copy(b, data) sr.n = sr.n + n return n, nil } n = copy(b, data) sr.n = sr.n + n return n, nil } func NewReader(in string) *StringReader { sr := new(StringReader) sr.data = in return sr } func main() { str := "Hello World" sr := NewReader(str) data := make([]byte, 10) n, err := sr.Read(data) for err == nil { fmt.Println(n, string(data[0:n])) n, err = sr.Read(data) } }
7.5:io包中的LimitReader函数接受一个io.Reader r和字节数n,返回一个Reader,该返回值从r读取数据,但在读取n字节后报告文件结束,请实现该函数。
func LimitReader(r io.Reader,n int64) io.Reader
package main import ( "fmt" "io" "os" ) type LimitedReader struct { Reader io.Reader Limit int current int } func (r *LimitedReader) Read(b []byte) (int, error) { if r.current >= r.Limit { return 0, io.EOF } if r.current+len(b) > r.Limit { b = b[:r.Limit-r.current] } n, err := r.Reader.Read(b) if err != nil { return n, err } r.current += n return n, nil } func LimitReader(r io.Reader, limit int) io.Reader { lr := LimitedReader{ Reader: r, Limit: limit, } return &lr } func main() { file, err := os.Open("limit.txt") // 1234567890 if err != nil { panic(err) } defer file.Close() lr := LimitReader(file, 5) buf := make([]byte, 10) n, err := lr.Read(buf) if err != nil { panic(err) } fmt.Println(n, buf) // 5 [49 50 51 52 53 0 0 0 0 0] }
7.8:(先实现一部分)将多个排序方法存到一个slice中,先按最后的方法排序,再按之前的方法排序。
package main import ( "fmt" "sort" ) type book struct { name string price float64 author string } type byFunc func(i, j int) bool type tableSlice struct { lists []*book lessFuncs []byFunc } func (ts tableSlice) Len() int { return len(ts.lists) } func (ts tableSlice) Swap(i, j int) { ts.lists[i], ts.lists[j] = ts.lists[j], ts.lists[i] } func (ts tableSlice) Less(i, j int) bool { for t := len(ts.lessFuncs) - 1; t >= 0; t-- { if ts.lessFuncs[t](i, j) { return true } else if !ts.lessFuncs[t](j, i) { continue } else { return false } } return false } func (ts tableSlice) byName(i, j int) bool { return ts.lists[i].name < ts.lists[j].name } func (ts tableSlice) byPrice(i, j int) bool { return ts.lists[i].price < ts.lists[j].price } func main() { book1 := book{"GoLang", 65.50, "Aideng"} book2 := book{"PHP", 45.50, "Sombody"} book3 := book{"C", 45.50, "Tan"} ts := tableSlice{ lists: []*book{&book1, &book2, &book3}, } ts.lessFuncs = []byFunc{ts.byName, ts.byPrice} sort.Sort(ts) for _, book := range ts.lists { fmt.Println(*book) } }
7.10:写一个函数IsPalindrome(s sort.Interface)bool判断一个序列是否是回文。
package palindrome import ( "fmt" "sort" ) func IsPalindrome(s sort.Interface) bool { if s.Len() == 0 { return false } i, j := 0, s.Len()-1 for i < j { if !s.Less(i, j) && !s.Less(j, i) { i++ j-- } else { return false } } return true } func main() { a := []int{1, 2, 3, 2, 1} fmt.Println(IsPalindrome(sort.IntSlice(a))) // true a = []int{2, 1, 3, 4, 5} fmt.Println(IsPalindrome(sort.IntSlice(a))) //false a = []int{1} fmt.Println(IsPalindrome(sort.IntSlice(a))) // true a = []int{} fmt.Println(IsPalindrome(sort.IntSlice(a))) // false }