mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 05:33:04 +08:00
* ch10.1 OK
This commit is contained in:
@@ -209,11 +209,103 @@ type Rect2 struct {Min, Max *Point }
|
||||
|
||||
**递归结构体**
|
||||
|
||||
**练习9.2**
|
||||
结构体类型可以通过自身来定义。在结构体变量是链表或二叉树的元素(通常叫节点)时,这种方法会特别有用,此时节点包含指向临近节点的链接(地址)。如下所示,链表中的`su`,树中的`ri`h和`le`分别是指向另一个节点变量的指针。
|
||||
|
||||
通过使用 unsafe 包中的方法来测试你电脑上一个整型变量占用多少个字节。
|
||||
链表:
|
||||
|
||||

|
||||
|
||||
这块的data域用于存放有些数据(比如float64),su指针指向后继节点。
|
||||
|
||||
Go代码:
|
||||
|
||||
```go
|
||||
type Node struct {
|
||||
data float64
|
||||
su *Node
|
||||
}
|
||||
```
|
||||
|
||||
链表中的第一个元素叫`head`,它指向第二个元素;最后一个元素叫`tail`,它没有后继元素,所以它的su为nil值。当然真实的链接会有很多数据节点,并且链表可以动态增长或收缩。
|
||||
|
||||
同样地可以定义一个双向链表,它有一个前趋节点pr和一个后继节点su:
|
||||
|
||||
```go
|
||||
type Node struct {
|
||||
pr *Node
|
||||
data float64
|
||||
su *su
|
||||
}
|
||||
```
|
||||
|
||||
二叉树:
|
||||
|
||||

|
||||
|
||||
二叉树中每个节点最多能链接至两个节点:左节点(le)和右节点(ri),这两个节点本身又可以有左右节点,依次类推。树的顶层节点叫根节点(`root`),底层没有子节点的节点叫叶子节点(`leaves`),叶子节点的le和ri指针为空值。在Go中可以如下定义树:
|
||||
|
||||
```go
|
||||
type Tree strcut {
|
||||
le *Tree
|
||||
data float64
|
||||
ri *Tree
|
||||
}
|
||||
```
|
||||
|
||||
**结构体转换**
|
||||
|
||||
Go中的类型转换遵循严格的规则。当为结构体定义了一个alias类型时,此结构体类型和它的alias类型都有相同的底层类型,它们可以如[Listing 10.3]那样互相转换,同时需要注意其中非法赋值或转换引起的编译错误:
|
||||
|
||||
```go
|
||||
package main
|
||||
import "fmt"
|
||||
|
||||
type number struct {
|
||||
f float32
|
||||
}
|
||||
|
||||
type nr number // alias type
|
||||
|
||||
func main() {
|
||||
a := number{5.0}
|
||||
b := nr{5.0}
|
||||
// var i float32 = b // compile-error: cannot use b (type nr) as type
|
||||
float32 in assignment
|
||||
// var i = float32(b) // compile-error: cannot convert b (type nr) to
|
||||
type float32
|
||||
// var c number = b // compile-error: cannot use b (type nr) as type number in assignment
|
||||
// needs a conversion:
|
||||
var c = number(b)
|
||||
fmt.Println(a, b, c)
|
||||
}
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
{5} {5} {5}
|
||||
|
||||
**练习**
|
||||
|
||||
*练习 10.1*
|
||||
|
||||
vcard.go:定义结构体Address和VCard,后者包含一个人的名字、地址编号、出生日期和图像,试着选择正确的数据类型。构建一个自己的vcard并打印它的内容。
|
||||
|
||||
提示:
|
||||
|
||||
VCard必须包含住址,它应该以值类型还是以指针类型放在VCard中呢?
|
||||
|
||||
第二种会好点,因为它占用内存少。包含一个名字和两个指向地址的指针的Address结构体可以使用%v打印:
|
||||
|
||||
{Kersschot 0x126d2b80 0x126d2be0}
|
||||
|
||||
*练习 10.2* 修改*persionext1.go*,使它的参数upPerson不是一个指针,解释下二者的区别。
|
||||
|
||||
*练习 10.3* point.go:使用坐标X、Y定义一个二维Point结构体。同样地,对一个三维点使用它的极坐标定义一个Polar结构体。实现一个Abs()方法来计算一个Point表示的向量的长度,实现一个Scale方法,它将点的坐标乘以一个尺度因子(提示:使用math包里的Sqrt函数)( function Scale that multiplies the coordinates of a point with a scale
|
||||
factor)
|
||||
|
||||
*练习 10.3* rectangle.go:定义一个Rectangle结构体,它的长和宽是int类型,并定义方法Area()和Primeter()并测试
|
||||
|
||||
## 链接
|
||||
- [目录](directory.md)
|
||||
- 上一节:[10 结构(struct)与方法(method)](10.0.md)
|
||||
- 下一节:[regexp 包](09.2.md)
|
||||
- 下一节:[10.2 使用工厂方法创建结构体](10.2.md)
|
||||
|
BIN
eBook/images/10.1_fig10.3.jpg
Normal file
BIN
eBook/images/10.1_fig10.3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
BIN
eBook/images/10.1_fig10.4.jpg
Normal file
BIN
eBook/images/10.1_fig10.4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Reference in New Issue
Block a user