- 繼承(結構體嵌入)
- 多態(接口實現和空接口)
1. 繼承(結構體嵌入)
Go 語言沒有傳統的面向對象的繼承機制,但可以通過“結構體嵌入”實現類似繼承的效果。
- 結構體嵌入:在結構體中嵌入另一個結構體,使得子結構體可以直接訪問父結構體的字段和方法。
- 字段重寫:若子結構體定義了與嵌入的結構體同名的字段,則可以認為“重寫”了父結構體的同名字段,訪問時默認訪問子結構體自己的字段,若需要訪問父結構體的字段,則使用
StructName.FieldName
。
代碼示例:
// 文件名: 03_inheritance.go
package mainimport "fmt"// 定義父類結構體 Person1
type Person1 struct {name stringage int
}// 定義另一個父類結構體 Person2(用于展示多個繼承時的處理,字段沖突時需要顯式區分)
// type Person2 struct {
// name string
// age int
// }// 定義子類結構體 Teacher,通過嵌入 Person1 來實現繼承
type Teacher struct {Person1 // 嵌入 Person1,實現繼承// 如果想繼承多個,則可以嵌入 Person2,但注意字段會沖突,需要通過顯式調用來區分// Person2 // 多繼承示例subject stringname int // 子類中重寫了 name 字段(此字段會覆蓋 Person1 中的同名字段)
}// 為 Person1 定義一個方法
func (p *Person1) Hello() {fmt.Println("I am Person1....")
}func main() {// 通過字面量實例化 Teacher,初始化 Person1 部分和子類特有字段t2 := Teacher{Person1: Person1{"zhangsan", 12},subject: "math",}fmt.Printf("t2: %+v\n", t2)// 先實例化一個 Person1 對象,然后將其賦值給 Teacher 的 Person1 字段p1 := Person1{"mikodo", 19}t3 := Teacher{Person1: p1, subject: "golang"}fmt.Printf("t3: %+v\n", t3)// 調用繼承的方法t2.Hello() // 等效于 t2.Person1.Hello()// 演示字段重寫t2.name = 100 // 修改 Teacher 中的 name 字段(子類自己的字段)t2.Person1.name = "luobozi" // 修改嵌入的 Person1 的 name 字段fmt.Printf("t2 after change: %+v\n", t2)
}
說明:
- 結構體
Teacher
嵌入了Person1
,因此可以直接調用Person1
的方法,如Hello()
。 - 子類
Teacher
定義了自己的name
字段,這樣在訪問時默認訪問的是Teacher.name
;如需要訪問父結構體中的name
則使用Teacher.Person1.name
。
2. 多態
Go 語言多態主要通過接口(interface)實現。
- 接口定義:接口定義了一組方法,任何實現了這些方法的類型都被視為該接口類型。
- 鴨子類型:Go 的多態不關心具體類型,只關心是否具有接口所需的方法。
- 空接口:空接口
interface{}
可以表示任意類型,相當于其他語言的 Object 類型。
代碼示例:
// 文件名: 03_polymorphism.go
package mainimport "fmt"// 定義 MoneyPay 接口,要求實現 pay 方法
type MoneyPay interface {pay()
}// 定義空接口類型(可以代表任何數據類型)
type kong interface{}// 定義 ZFB 結構體,代表支付寶
type ZFB struct {name string
}// 定義 WX 結構體,代表微信
type WX struct {name string
}// 為 ZFB 綁定方法,實現 MoneyPay 接口
func (z *ZFB) pay() {fmt.Println("this is zfb pay")
}// 為 WX 綁定方法,實現 MoneyPay 接口
func (w *WX) pay() {fmt.Println("this is wx pay")
}// 定義函數 FinPay,接收 MoneyPay 接口類型的參數
func FinPay(p MoneyPay) {p.pay()
}func main() {// 實例化支付寶和微信對象(均為指針類型)z1 := &ZFB{"支付寶"}w1 := &WX{"微信"}// 接口變量可以接收實現該接口的任何對象var j1, j2 MoneyPayj1 = z1j2 = w1fmt.Println("j1 and j2:", j1, j2)// 通過接口調用支付方法,實現多態FinPay(z1)FinPay(w1)// 空接口示例,空接口可以保存任意類型的數據m1 := map[string]kong{"name": "luobozi","age": 18,}fmt.Println("空接口 map:", m1)// 類型斷言:將空接口中的數據轉換為具體類型,然后進行計算result := m1["age"].(int) + 10fmt.Println("斷言后計算結果:", result)
}
說明:
- 接口
MoneyPay
定義了pay()
方法,ZFB
和WX
結構體分別通過指針接收者實現了該方法,從而都滿足MoneyPay
接口。 - 函數
FinPay
接收接口類型參數,可以接受任何實現了pay()
方法的類型,體現多態性。 - 空接口
kong
可以存放任意數據,通過類型斷言可以獲取具體類型值。
總結
本篇代碼整理涵蓋了 Go 語言中“繼承和多態”的相關知識點:
-
繼承(結構體嵌入):
- 利用結構體嵌入實現類似繼承的效果
- 字段重寫示例:子類中定義同名字段覆蓋父類字段
- 調用嵌入結構體的方法
-
多態:
- 通過接口定義多態行為,只要類型實現了接口方法,就能被當作該接口類型使用
- 演示了如何使用空接口存儲任意類型數據,并通過類型斷言獲取具體類型