Go 語(yǔ)言不支持面向?qū)ο缶幊陶Z(yǔ)言中那樣的構(gòu)造子方法,但是可以很容易的在 Go 中實(shí)現(xiàn) “構(gòu)造子工廠”方法。為了方便通常會(huì)為類型定義一個(gè)工廠,按慣例,工廠的名字以 new 或 New 開(kāi)頭。假設(shè)定義了如下的 File 結(jié)構(gòu)體類型:
type File struct {
fd int // 文件描述符
name string // 文件名
}
下面是這個(gè)結(jié)構(gòu)體類型對(duì)應(yīng)的工廠方法,它返回一個(gè)指向結(jié)構(gòu)體實(shí)例的指針:
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
return &File{fd, name}
}
然后這樣調(diào)用它:
f := NewFile(10, "./test.txt")
在 Go 語(yǔ)言中常常像上面這樣在工廠方法里使用初始化來(lái)簡(jiǎn)便的實(shí)現(xiàn)構(gòu)造函數(shù)。
如果 File
是一個(gè)結(jié)構(gòu)體類型,那么表達(dá)式 new(File)
和 &File{}
是等價(jià)的。
這可以和大多數(shù)面向?qū)ο缶幊陶Z(yǔ)言中笨拙的初始化方式做個(gè)比較:File f = new File(...)
。
我們可以說(shuō)是工廠實(shí)例化了類型的一個(gè)對(duì)象,就像在基于類的OO語(yǔ)言中那樣。
如果想知道結(jié)構(gòu)體類型T的一個(gè)實(shí)例占用了多少內(nèi)存,可以使用:size := unsafe.Sizeof(T{})
。
如何強(qiáng)制使用工廠方法
通過(guò)應(yīng)用可見(jiàn)性規(guī)則參考4.2.1節(jié)、9.5 節(jié)就可以禁止使用 new 函數(shù),強(qiáng)制用戶使用工廠方法,從而使類型變成私有的,就像在面向?qū)ο笳Z(yǔ)言中那樣。
type matrix struct {
...
}
func NewMatrix(params) *matrix {
m := new(matrix) // 初始化 m
return m
}
在其他包里使用工廠方法:
package main
import "matrix"
...
wrong := new(matrix.matrix) // 編譯失?。╩atrix 是私有的)
right := matrix.NewMatrix(...) // 實(shí)例化 matrix 的唯一方式
new 和 make 這兩個(gè)內(nèi)置函數(shù)已經(jīng)在第 7.2.4 節(jié)通過(guò)切片的例子說(shuō)明過(guò)一次。
現(xiàn)在為止我們已經(jīng)見(jiàn)到了可以使用 make()
的三種類型中的其中兩個(gè):
slices / maps / channels(見(jiàn)第 14 章)
下面的例子說(shuō)明了在映射上使用 new 和 make 的區(qū)別以及可能發(fā)生的錯(cuò)誤:
示例 10.4 new_make.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) // 編譯錯(cuò)誤:cannot make type Bar
(*z).thingOne = "hello"
(*z).thingTwo = 1
// OK
x := make(Foo)
x["x"] = "goodbye"
x["y"] = "world"
// NOT OK
u := new(Foo)
(*u)["x"] = "goodbye" // 運(yùn)行時(shí)錯(cuò)誤!! panic: assignment to entry in nil map
(*u)["y"] = "world"
}
試圖 make()
一個(gè)結(jié)構(gòu)體變量,會(huì)引發(fā)一個(gè)編譯錯(cuò)誤,這還不是太糟糕,但是 new()
一個(gè)映射并試圖使用數(shù)據(jù)填充它,將會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤! 因?yàn)?new(Foo)
返回的是一個(gè)指向 nil
的指針,它尚未被分配內(nèi)存。所以在使用 map
時(shí)要特別謹(jǐn)慎。