Files
the-way-to-go_ZH_CN/eBook/10.2.md
2015-07-04 15:45:26 +08:00

112 lines
3.2 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.2 使用工厂方法创建结构体实例
## 10.2.1 结构体工厂
Go语言不支持面向对象编程语言中那样的构造子方法但是可以很容易的在Go中实现“构造子工厂“方法。为了方便通常会为类型定义一个工厂俺惯例工厂的名字以new或New开头。假设定义了如下的File结构体类型
```go
type File struct {
fd int // 文件描述符
name string // 文件名
}
```
下面是这个结构体类型对应的工厂方法,它返回一个指向结构体实例的指针:
```go
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
return &File(id, name)
}
```
然后这样调用它:`f := NewFile(10, "./test.txt")`
在Go语言中常常像上面这样在工厂方法里使用初始化来简便的实现构造子。
如果`File`是一个结构体类型,那么表达式`new(File)``&File{}`是等价的。
这可以和大多数面向对象编程语言中笨拙的初始化方式做个比较:`File f = new File(...)`
我们可以说是工厂实例化了类型的一个对象就像在基于类的OO语言中那样。
如果想知道结构体类型T的一个实例占用了多少内存可以使用`size := unsafe.Sizeof(T{})`
**如何强制使用工厂方法**
通过应用可见性规则参考4.2.19.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章
下面的例子来说明了在映射上使用new和make的区别以及可能的发生的错误
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.3 使用结构体定制包](10.3.md)