Files
the-way-to-go_ZH_CN/eBook/10.7.md
2015-10-25 00:22:39 +08:00

110 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 10.7 类型的 String() 方法和格式化描述符
当定义一个了有很多方法的类型时,十之八九你会使用 `String()` 方法来定制类型的字符串形式的输出,换句话说:一种可阅读性和打印性的输出。如果类型定义了 `String()` 方法,它会被用在 `fmt.Printf()` 中生成默认的输出:等同于使用格式化描述符 `%v` 产生的输出。还有 `fmt.Print()``fmt.Println()` 也会自动使用 `String()` 方法。
我们使用第 10.4 节中程序的类型来进行测试:
示例 10.22 method_string.go
```go
package main
import (
"fmt"
"strconv"
)
type TwoInts struct {
a int
b int
}
func main() {
two1 := new(TwoInts)
two1.a = 12
two1.b = 10
fmt.Printf("two1 is: %v\n", two1)
fmt.Println("two1 is:", two1)
fmt.Printf("two1 is: %T\n", two1)
fmt.Printf("two1 is: %#v\n", two1)
}
func (tn *TwoInts) String() string {
return "(" + strconv.Itoa(tn.a) + "/" + strconv.Itoa(tn.b) + ")"
}
```
输出:
two1 is: (12/10)
two1 is: (12/10)
two1 is: *main.TwoInts
two1 is: &main.TwoInts{a:12, b:10}
当你广泛使用一个自定义类型时,最好为它定义 `String()`方法。从上面的例子也可以看到,格式化描述符 `%T` 会给出类型的完全规格,`%#v` 会给出实例的完整输出,包括它的字段(在程序自动生成 `Go` 代码时也很有用)。
**备注**
不要在 `String()` 方法里面调用涉及 `String()` 方法的方法,它会导致意料之外的错误,比如下面的例子,它导致了一个无限迭代(递归)调用(`TT.String()` 调用 `fmt.Sprintf`,而 `fmt.Sprintf` 又会反过来调用 `TT.String()`...),很快就会导致内存溢出:
```go
type TT float64
func (t TT) String() string {
return fmt.Sprintf("%v", s)
}
t. String()
```
**练习 10.12** type_string.go
给定结构体类型 T:
```go
type T struct {
a int
b float32
c string
}
```
`t`: `t := &{7, -2.35, "abc\tdef"}`。给 T 定义 `String()`,使得 `fmt.Printf("%v\n", t)` 输出:`7 / -2.350000 / "abc\tdef"`
**练习 10.13** celsius.go
为 float64 定义一个别名类型 `Celsius`,并给它定义 `String()`,它输出一个十进制数和 °C 表示的温度值。
**练习 10.14** days.go
为 int 定义一个别名类型 `Day`,定义一个字符串数组它包含一周七天的名字,为类型 `Day` 定义 `String()` 方法,它输出星期几的名字。使用 `iota` 定义一个枚举常量用于表示一周的中每天MO、TU...)。
**练习 10.15** timezones.go
为 int 定义别名类型 `TZ`,定义一些常量表示时区,比如 UTC定义一个 map它将时区的缩写映射为它的全称比如`UTC -> "Universal Greenwich time"`。为类型 `TZ` 定义 `String()` 方法,它输出时区的全称。
**练习 10.16** stack_arr.go/stack_struct.go
实现栈stack数据结构
![](images/10.7_fig.jpg?raw=true)
它的格子包含数据,比如整数 i、j、k 和 l 等等,格子从底部(索引 0至顶部索引 n来索引。这个例子中假定 `n=3`,那么一共有 4 个格子。
一个新栈中所有格子的值都是 0。
push 将一个新值放到栈的最顶部一个非空(非零)的格子中。
pop 获取栈的最顶部一个非空非零的格子的值。现在可以理解为什么栈是一个后进先出LIFO的结构了吧。
为栈定义一 `Stack` 类型,并为它定义一个 `Push``Pop` 方法,再为它定义 `String()` 方法(用于调试)它输出栈的内容,比如:`[0:i] [1:j] [2:k] [3:l]`
1stack_arr.go使用长度为 4 的 int 数组作为底层数据结构。
2stack_struct.go使用包含一个索引和一个 int 数组的结构体作为底层数据结构,所以表示第一个空闲的位置。
3使用常量 LIMIT 代替上面表示元素个数的 4 重新实现上面的 1和 2使它们更具有一般性。
## 链接
- [目录](directory.md)
- 上一节:[方法](10.6.md)
- 下一节:[垃圾回收和 SetFinalizer](10.8.md)