1. 自定義類型格式
用戶自定義類型使用關鍵字 type
,其語法格式是:
type newType oldType
oldType
可以是自定義類型、預聲明類型、未命名類型中的任意一種。
newType
是新類型的標識符,與 oldType
具有相同的底層類型,並且都繼承了底層類型的操作集合(這裏的操作不是方法,比如底層類型是 map
,支持 range
迭代訪問,則新類型也可以使用 range
迭代訪問) 。除此之外, newType
和 oldType
是兩個完全不同的類型, newType
不會繼承 oldType
的方法。
無論 oldType
是什麼類型,使用 type
聲明的新類型都是一種命名類型,也就是說,自定義類型都是命名類型。
type INT int //INT 是一個使用預聲明類型聲明的自定義類型
type Map map[string]string //Map 是一個使用類型字面量聲明的自定義類型
type myMap Map //myMap 是一個自定義類型Map 聲明的自定義類型
// INT, Map 、myMap 都是命名類型
2. 自定義 struct 類型
struct
類型是 Go
語言自定義類型的普遍的形式,是 Go
語言類型擴展的基石,也是 Go
語言面向對象承載的基礎。
前面章節將 struct
劃爲未命名類型,那時的 struct
是使用字面量來表示的,如果使用 type
語句聲明,則這個新類型就是命名類型。例如:
// 使用 type 自定義的結構類型屬於命名類型
type XXXName struct {
field1 type1
field2 type2
}
// errorString 是一個自定義結構類型,也是命名類型
type errorString struct {
s string
}
// 結構字面量屬於未命名類型
struct {
field1 type1
field2 type2
}
// struct{} 是非命名類型空結構
var s = struct{}{}
2.1 struct 初始化
以 Person
結構爲例來講一下結構的初始化的方法。例如:
type Person struct {
name string
age int
}
- 按照字段順序進行初始化
// 以下三種寫法都可以
a := Person{"Tom", 25}
b := Person{
"Tom",
25}
c := Person{
"Tom",
25, // 必須加逗號
}
不推薦這種寫法,一旦結構體增加字段,則需要重新修改初始化語句的順序。
- 指定字段名進行初始化
推薦這種寫法,結構體增加字段後,無需修改原有初始化語句的順序。
a := Person{name:"Tom", age:25}
b := Person{
name:"Tom",
age:25}
b := Person{
name:"Tom",
age:25, // 加逗號
} // 初始化語句結尾的 } 獨佔一行,則最後一個字段的後面一定要帶上逗號。
- 使用
new
創建內置函數,字段默認初始化爲其類型的零值, 返回值是指向結構的指針。例如:
p := new(Person)
// 此時 name 爲 "", age 爲 0
這種方法不常用,一般使用 struct
都不會將所有字段初始化爲零值。
- 一次初始化一個字段
p := Person{}
p.name = "Tom"
p.age = 25
這種方法不常用,這是一種結構化的編程思維,沒有封裝,違背了 struct
本身抽象封裝的理念。
- 使用構造函數進行初始化
這是推薦的一種方法,當結構發生變化時,構造函數可以屏蔽細節。下面是標準庫中 errors
的 New
函數示例。
//${GOROOT)/src/errors/errors.go
//New returns an error that formats as the given text.
func New(text string) error {
return &errorString{text}
}
//errorStr 工ng is a trivial implementation of error .
type errorString struct {
s string
}
2.2 結構字段的特點
結構的字段可以是任意的類型,基本類型、接口類型、指針類型、函數類型都可以作爲 struct
的字段。結構字段的類型名必須唯一, struct
字段類型可以是普通類型,也可以是指針。另外,結構支持內嵌自身的指針,這也是實現樹形和鏈表等複雜數據結構的基礎。例如:
// 標準庫container/list
type Element struct {
// 指向自身類型的指針
next, prev *Element
list *List
Value interface{}
}
2.3 匿名字段
在定義 struct
的過程中,如果字段只給出字段類型,沒有給出宇段名, 則稱這樣的字段爲“匿名字段”。被匿名嵌入的字段必須是命名類型或命名類型的指針,類型字面量不能作爲匿名字段使用。
匿名字段的字段名默認就是類型名,如果匿名字段是指針類型,則默認的字段名就是指針指向的類型名。但一個結構體裏面不能同時存在某一類型及其指針類型的匿名字段, 原因是二者的字段名相等。如果嵌入的字段來自其他包,則需要加上包名,並且必須是其他包可以導出的類型。示例如下:
3. 自定義接口類型
接口字面量是非命名類型,但自定義接口類型是命名類型。自定義接口類型同樣使用 type
關鍵字聲明。示例如下:
// interface{} 是接口字面量類型標識, 所以 i 是非命名類型交量
var i interface{}
// Reader 是自定義接口類型,屬於命名類型
type Reader interface {
Read (p []byte) (n int , err error )
}