mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-11 22:53:43 +08:00
精校:10.2-10.4
This commit is contained in:
@@ -19,4 +19,4 @@ Golang 编程:245386165
|
||||
|
||||
|更新日期 |更新内容
|
||||
|----------|------------------
|
||||
|2015-08-14|10.1 结构体定义
|
||||
|2015-08-16|10.4 带标签的结构体
|
3
TOC.md
3
TOC.md
@@ -81,3 +81,6 @@
|
||||
- 9.11 [在 Go 程序中使用外部库](eBook/09.11.md)
|
||||
- 第10章:[结构(struct)与方法(method)](eBook/10.0.md)
|
||||
- 10.1 [结构体定义](eBook/10.1.md)
|
||||
- 10.2 [使用工厂方法创建结构体实例](eBook/10.2.md)
|
||||
- 10.3 [使用自定义包中的结构体](eBook/10.3.md)
|
||||
- 10.4 [带标签的结构体](eBook/10.4.md)
|
@@ -2,7 +2,7 @@
|
||||
|
||||
## 10.2.1 结构体工厂
|
||||
|
||||
Go语言不支持面向对象编程语言中那样的构造子方法,但是可以很容易的在Go中实现“构造子工厂“方法。为了方便通常会为类型定义一个工厂,俺惯例,工厂的名字以new或New开头。假设定义了如下的File结构体类型:
|
||||
Go 语言不支持面向对象编程语言中那样的构造子方法,但是可以很容易的在 Go 中实现 “构造子工厂“ 方法。为了方便通常会为类型定义一个工厂,俺惯例,工厂的名字以 new 或 New 开头。假设定义了如下的 File 结构体类型:
|
||||
|
||||
```go
|
||||
type File struct {
|
||||
@@ -22,21 +22,26 @@ func NewFile(fd int, name string) *File {
|
||||
return &File(id, name)
|
||||
}
|
||||
```
|
||||
然后这样调用它:`f := NewFile(10, "./test.txt")`
|
||||
|
||||
在Go语言中常常像上面这样在工厂方法里使用初始化来简便的实现构造子。
|
||||
然后这样调用它:
|
||||
|
||||
如果`File`是一个结构体类型,那么表达式`new(File)`和`&File{}`是等价的。
|
||||
```go
|
||||
f := NewFile(10, "./test.txt")
|
||||
```
|
||||
|
||||
在 Go 语言中常常像上面这样在工厂方法里使用初始化来简便的实现构造子。
|
||||
|
||||
如果 `File` 是一个结构体类型,那么表达式 `new(File)` 和 `&File{}` 是等价的。
|
||||
|
||||
这可以和大多数面向对象编程语言中笨拙的初始化方式做个比较:`File f = new File(...)`。
|
||||
|
||||
我们可以说是工厂实例化了类型的一个对象,就像在基于类的OO语言中那样。
|
||||
|
||||
如果想知道结构体类型T的一个实例占用了多少内存,可以使用:`size := unsafe.Sizeof(T{})`
|
||||
如果想知道结构体类型T的一个实例占用了多少内存,可以使用:`size := unsafe.Sizeof(T{})`。
|
||||
|
||||
**如何强制使用工厂方法**
|
||||
|
||||
通过应用可见性规则(参考4.2.1,9.5)就可以禁止使用new函数,强制用户使用工厂方法,从而使类型变成私有的,就像在OO语言中那样。
|
||||
通过应用可见性规则(参考第 4.2.1、9.5 节)就可以禁止使用 new 函数,强制用户使用工厂方法,从而使类型变成私有的,就像在面向对象语言中那样。
|
||||
|
||||
```go
|
||||
type matrix struct {
|
||||
@@ -44,7 +49,7 @@ type matrix struct {
|
||||
}
|
||||
|
||||
func NewMatrix(params) *matrix {
|
||||
m := new(matrix) // 初始化m
|
||||
m := new(matrix) // 初始化 m
|
||||
return m
|
||||
}
|
||||
```
|
||||
@@ -55,21 +60,21 @@ func NewMatrix(params) *matrix {
|
||||
package main
|
||||
import "matrix"
|
||||
...
|
||||
wrong := new(matrix.matrix) // 编译失败(matrix是私有的)
|
||||
right := matrix.NewMatrix(...) // 实例化matrix的唯一方式
|
||||
wrong := new(matrix.matrix) // 编译失败(matrix 是私有的)
|
||||
right := matrix.NewMatrix(...) // 实例化 matrix 的唯一方式
|
||||
```
|
||||
|
||||
## 10.2.2 map和struct vs new()和make()
|
||||
## 10.2.2 map 和 struct vs new() 和 make()
|
||||
|
||||
new和make这两个内置函数已经在[7.2.4](7.2.md)节通过切片的例子说明过一次。
|
||||
new 和 make 这两个内置函数已经在第 [7.2.4](7.2.md) 节通过切片的例子说明过一次。
|
||||
|
||||
现在为止我们已经见到了可以使用make()的三种类型中的其中两个:
|
||||
现在为止我们已经见到了可以使用 `make()` 的三种类型中的其中两个:
|
||||
|
||||
slices / maps / channels(见第14章)
|
||||
slices / maps / channels(见第 14 章)
|
||||
|
||||
下面的例子来说明了在映射上使用new和make的区别,以及可能的发生的错误:
|
||||
下面的例子来说明了在映射上使用 new 和 make 的区别,以及可能的发生的错误:
|
||||
|
||||
Listing 10.4—new_make.go(不能编译)
|
||||
示例 10.4 new_make.go(不能编译)
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -103,9 +108,10 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
试图make()一个结构体变量,会引发一个编译错误,这还不是太糟糕,但是new()一个映射并试图使用数据填充它,将会引发运行时错误! 因为new(Foo)返回的是一个指向nil的指针,它尚未被分配内存。所以在使用map时要特别谨慎。
|
||||
试图 `make()` 一个结构体变量,会引发一个编译错误,这还不是太糟糕,但是 `new()` 一个映射并试图使用数据填充它,将会引发运行时错误! 因为 `new(Foo)` 返回的是一个指向 `nil` 的指针,它尚未被分配内存。所以在使用 `map` 时要特别谨慎。
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一节:[10 结构(struct)与方法(method)](10.0.md)
|
||||
- 下一节:[10.3 使用结构体定制包](10.3.md)
|
||||
- 上一节:[结构体定义)](10.1.md)
|
||||
- 下一节:[使用自定义包中的结构体](10.3.md)
|
||||
|
@@ -1,8 +1,9 @@
|
||||
# 10.3 使用自定义包中的结构体
|
||||
|
||||
下面的例子中,main.go使用了一个结构体,它来自**submap?** struct_pack下的包structPack。
|
||||
下面的例子中,main.go 使用了一个结构体,它来自 struct_pack 下的包 structPack。
|
||||
|
||||
示例 10.5 structPack.go:
|
||||
|
||||
Listing 10.5—structPack.go:
|
||||
```go
|
||||
package structPack
|
||||
|
||||
@@ -12,7 +13,8 @@ type ExpStruct struct {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 10.6—main.go:
|
||||
示例 10.6 main.go:
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
@@ -36,6 +38,7 @@ func main() {
|
||||
Mf1 = 16.000000
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一节:[10.2 使用工厂方法创建结构体实例](10.2.md)
|
||||
- 下一节:[10.4 带标签的结构体](10.4.md)
|
||||
- 上一节:[使用工厂方法创建结构体实例](10.2.md)
|
||||
- 下一节:[带标签的结构体](10.4.md)
|
||||
|
@@ -1,10 +1,11 @@
|
||||
# 10.4 带标签的结构体
|
||||
|
||||
结构体中的字段除了有名字和类型外,还可以有一个可选的标签(tag):它是一个附属于字段的字符串,可以是文档或其他的重要标记。标签的内容不可以在一般的编程中使用,只有包`reflect`能获取它。我们将在下一章(11.10)中深入的探讨`reflect`包,它可以在运行时自省类型、属性和方法,比如:在一个变量上调用` reflect.TypeOf()`可以获取变量的正确类型,如果变量是一个结构体类型,就可以通过Field来索引结构体的字段,然后就可以使用Tag属性。
|
||||
结构体中的字段除了有名字和类型外,还可以有一个可选的标签(tag):它是一个附属于字段的字符串,可以是文档或其他的重要标记。标签的内容不可以在一般的编程中使用,只有包 `reflect` 能获取它。我们将在下一章(第 11.10 节)中深入的探讨 `reflect`包,它可以在运行时自省类型、属性和方法,比如:在一个变量上调用 `reflect.TypeOf()` 可以获取变量的正确类型,如果变量是一个结构体类型,就可以通过 Field 来索引结构体的字段,然后就可以使用 Tag 属性。
|
||||
|
||||
Listing 10.7—struct_tag.go展示了如何使用它:
|
||||
```go
|
||||
package main
|
||||
示例 10.7 struct_tag.go:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -29,15 +30,16 @@ func refTag(tt TagType, ix int) {
|
||||
ixField := ttType.Field(ix)
|
||||
fmt.Printf("%v\n", ixField.Tag)
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
输出:
|
||||
输出:
|
||||
|
||||
An important answer
|
||||
The name of the thing
|
||||
How much there are
|
||||
|
||||
## 链接
|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一节:[10.3 使用自定义包中的结构体](10.3.md)
|
||||
- 下一节:[10.5 匿名字段和内嵌结构体](10.5.md)
|
||||
- 上一节:[使用自定义包中的结构体](10.3.md)
|
||||
- 下一节:[匿名字段和内嵌结构体](10.5.md)
|
||||
|
@@ -91,8 +91,8 @@
|
||||
- 10.4 [带标签的结构体](10.4.md)
|
||||
- 10.5 [匿名字段和内嵌结构体](10.5.md)
|
||||
- 10.6 [方法](10.6.md)
|
||||
- 10.7 [类型的String()方法和格式化描述符](10.7.md)
|
||||
- 10.8 [垃圾回收和SetFinalizer](10.8.md)
|
||||
- 10.7 [类型的 String() 方法和格式化描述符](10.7.md)
|
||||
- 10.8 [垃圾回收和 SetFinalizer](10.8.md)
|
||||
- 第11章:接口(interface)与反射(reflection)
|
||||
|
||||
## 第三部分:Go 高级编程
|
||||
|
Reference in New Issue
Block a user