EX 3.10
练习 3.10: 编写一个非递归版本的comma函数,使用bytes.Buffer代替字符串链接操作。
func comma(s string) string {
var buf bytes.Buffer
n := len(s)
fmt.Println(n)
if n <= 3 {
return s
}
for i := n; i > 0; i-- {
if i%3 == 0 && i != n {
buf.WriteByte(',')
}
buf.WriteByte(s[n-i])
}
return buf.String()
}
EX 3.11
练习 3.11: 完善comma函数,以支持浮点数处理和一个可选的正负号的处理。
func comma(s string) string {
var buf bytes.Buffer
mantissaStart := 0
if s[0] == '+' || s[0] == '-' {
buf.WriteByte(s[0])
mantissaStart = 1
}
mantissaEnd := strings.Index(s, ".")
if mantissaEnd == -1 {
mantissaEnd = len(s)
}
mantissa := s[mantissaStart:mantissaEnd]
n := len(mantissa)
if n <= 3 {
buf.WriteString(mantissa)
} else {
for i := n; i > 0; i-- {
if i%3 == 0 && i != n {
buf.WriteByte(',')
}
buf.WriteByte(mantissa[n-i])
}
}
buf.WriteString(s[mantissaEnd:])
return buf.String()
}
EX 3.12
练习 3.12: 编写一个函数,判断两个字符串是否是相互打乱的,也就是说它们有着相同的字符,但是对应不同的顺序。
// 一
func isAnagram1(a, b string) bool {
j := 0
for i := 0; i < len(a); i++ {
if strings.Count(a, a[i:i+1]) == strings.Count(b, a[i:i+1]) {
j++
}
}
if !strings.EqualFold(a, b) && j == len(a) && len(a) == len(b) {
return true
}
return false
}
// 二
func isAnagram2(a, b string) bool {
aFrep := make(map[rune]int)
for _, c := range a {
aFrep[c]++
}
bFrep := make(map[rune]int)
for _, c := range b {
bFrep[c]++
}
for k, v := range aFrep {
if bFrep[k] != v {
return false
}
}
for k, v := range bFrep {
if aFrep[k] != v {
return false
}
}
return true
}
// 三
func isAnagram3(a, b string) bool {
aFrep := make(map[rune]int)
for _, c := range a {
aFrep[c]++
}
bFrep := make(map[rune]int)
for _, c := range b {
bFrep[c]++
}
if reflect.DeepEqual(aFrep, bFrep) {
return true
}
return false
}
EX 3.13
练习 3.13: 编写KB、MB的常量声明,然后扩展到YB。
const (
KB = 1000
MB = 1000 * KB
GB = 1000 * MB
PB = 1000 * GB
)
EX 7.1
练习 7.1: 使用来自ByteCounter的思路,实现一个针对单词和行数的计数器。你会发现bufio.ScanWords非常的有用。
type WordCounter int
func (c *WordCounter) Write(p []byte) (int, error) {
scanner := bufio.NewScanner(bytes.NewReader(p))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
*c += WordCounter(1)
}
return 0, nil
}
type LineCounter int
func (c *LineCounter) Write(p []byte) (int, error) {
scanner := bufio.NewScanner(bytes.NewReader(p))
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
*c += LineCounter(1)
}
return 0, nil
}
EX 7.2
练习 7.2: 写一个带有如下函数签名的函数CountingWriter,传入一个io.Writer接口类型,返回一个把原来的Writer封装在里面的新的Writer类型和一个表示新的写入字节数的int64类型指针。
type ByteCounter struct {
w io.Writer
written int64
}
func (c *ByteCounter) Write(p []byte) (int, error) {
n, err := c.w.Write(p)
c.written += int64(n)
return n, err
}
func CountingWriter(w io.Writer) (io.Writer, *int64) {
c := ByteCounter{w, 0}
return &c, &c.written
}
EX 7.3
练习 7.3: 为在gopl.io/ch4/treesort (§4.4)中的*tree类型实现一个String方法去展示tree类型的值序列。
func (t *tree) String() string {
var s string
if t == nil {
return s
}
s += t.left.String()
if t.left != nil {
s += ", "
}
s += strconv.Itoa(t.value)
if t.right != nil {
s += ", "
}
s += t.right.String()
return s
}
EX 7.7
练习 7.7: 解释为什么帮助信息在它的默认值是20.0没有包含°C的情况下输出了°C。
因为 CelsiusFlag 拥有 Celsius 作为成员,而 Celsius 实现了 String 方法(实现了 fmt.Stringer 接口),
所以打印是会通过 Celsius.String() 输出