10.6-10.8

This commit is contained in:
Unknwon
2015-08-25 14:32:16 +08:00
parent ad7e49d1ec
commit 4951fb9105
8 changed files with 155 additions and 140 deletions

View File

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