From 1fa82a86c72ad6f01449896108b28c13be1136fc Mon Sep 17 00:00:00 2001 From: leisore Date: Sat, 4 Jul 2015 15:31:19 +0800 Subject: [PATCH] =?UTF-8?q?ch10.2=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eBook/10.2.md | 86 +++++++++++++++++++++++++++++++++++++++++++--- eBook/directory.md | 1 + 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/eBook/10.2.md b/eBook/10.2.md index cff818b..d656178 100644 --- a/eBook/10.2.md +++ b/eBook/10.2.md @@ -11,7 +11,7 @@ type File struct { } ``` -下面是这个结构体类型对应的工厂函数,它返回一个指向结构体实例的指针: +下面是这个结构体类型对应的工厂方法,它返回一个指向结构体实例的指针: ```go func NewFile(fd int, name string) *File { @@ -22,12 +22,90 @@ func NewFile(fd int, name string) *File { return &File(id, name) } ``` +调用它的例子:`f := NewFile(10, "./test.txt")` -**练习** +在Go语言中常常像上面这样在工厂方法里使用初始化简便的实现构造子。 -*练习 10.1* +如果`File`是一个结构体类型,那么表达式`new(File)`和`&File{}`是等价的。 + +可以和大多数面向对象编程语言中笨拙的初始化方式做个比较:`File f = new File(...)`。 + +我们可以说是工厂实例化了类型的一个对象,就像在基于类的OO语言中那样。 + +如果想知道结构体类型T的一个实例占用了多少内存,可以使用:`size := unsafe.Sizeof(T{})` + +*如果强制使用工程函数* + +通过使用可见性规则(参考4.2.1,9.5)就可以禁止使用new函数,强制用户使用工厂方法,从而有效地使类型变成私有的,就像在OO语言中那样。 + +```go +type matrix struct { + ... +} + +func NewMatrix(params) *matrix { + m := new(matrix) // 处初始化m + return m +} +``` + +在其他包里使用工厂方法: + +```go + package main + import "matrix" + ... + wrong := new(matrix.matrix) // 编译失败(matrix是私有的) + right := matrix.NewMatrix(...) // 实例化matrix的唯一方式 +``` + +## 10.2.2 map和struct vs new()和make()再探 + +new和make这两个内置函数已经在[7.2.4](7.2.md)节通过切片的例子说明过一次。 + +现在为止我们已经见到了可以使用make()的三种类型其中的两个: + + slices / maps / channels(见第14章) + +使用下面的例子来说明下在映射上使用它们的区别和可能的发生的错误: + +Listing 10.4—new_make.go(不能编译) + +```go +package main + +type Foo map[string]string +type Bar struct { + thingOne string + thingTwo int +} + +func main() { + // OK + y := new(Bar) + (*y).thingOne = "hello" + (*y).thingTwo = 1 + + // NOT OK + z := make(Bar) // 编译错误:cannot make type Bar + (*y).thingOne = "hello" + (*y).thingTwo = 1 + + // OK + x := make(Foo) + x["x"] = "goodbye" + x["y"] = "world" + + // NOT OK + u := new(Foo) + (*u)["x"] = "goodbye" // 运行时错误!! panic: assignment to entry in nil map + (*u)["y"] = "world" +} +``` + +试图make()一个结构体变量,会引发一个编译错误,这不是太糟糕,但是new()一个映射并试图使用数据填充它,将会引发运行时错误!new(Foo)会返回一个指向nil的指针,它尚未被分配内存。所以在使用map时要特别谨慎。 ## 链接 - [目录](directory.md) - 上一节:[10 结构(struct)与方法(method)](10.0.md) -- 下一节:[10.2 使用工厂方法创建结构体实例](10.2.md) +- 下一节:[10.3 使用结构体定制包](10.3.md) diff --git a/eBook/directory.md b/eBook/directory.md index f22b685..29fb9da 100644 --- a/eBook/directory.md +++ b/eBook/directory.md @@ -86,6 +86,7 @@ - 9.11 [在 Go 程序中使用外部库](09.11.md) - 第10章:[结构(struct)与方法(method)](10.0.md) - 10.1 [结构体定义](10.1.md) + - 10.2 [使用工厂方法创建结构体实例](10.2.md) - 第11章:接口(interface)与反射(reflection) ## 第三部分:Go 高级编程