抽象介紹:
在定義一個結構體的時候,實際上就是把一類事物的共有屬性(字段)和行為(方法) 提取出來,形成一個物理模型(模板),這種研究問題的方法稱為抽象。
封裝:
把抽象出的字段和對字段的操作封裝在一起,數據被保護在內部,程序的其它包只有通過被授權的操作(方法),才能對字段進行操作。
1)將結構體、字段(屬性)的首字母小寫
2)給結構體所在包提供一個工廠模式的函數,首字母大寫,類似一個構造函數
3)提供一個首字母大寫的Set方法(類似其它語言的public),用於對屬性判斷並賦值
model.go
package model import ( "fmt" ) type account struct { username string password string balance float64 } func NewAccount() *account { return &account{} } // 設置賬號 func (user *account) SetUsername(username string) { if len(username) < 6 && len(username) > 10 { fmt.Println("賬號長度必須是6到10位") return } user.username = username } func (user *account) GetUsername() string { return user.username } // 設置密碼 func (user *account) SetPassword(password string) { if len(password) != 6 { fmt.Println("密碼必須是6位") return } user.password = password } func (user *account) GetPassword() string { return user.password } // 設置余額 func (user *account) SetBalance(balance float64) { if balance < 20 { fmt.Println("余額必須大於20") return } user.balance = balance } func (user *account) GetBalance() float64 { return user.balance }
main.go
package main import ( "fmt" "model" ) func main() { user := model.NewAccount() user.SetUsername("admin123") user.SetPassword("123456") user.SetBalance(20) fmt.Println(user.GetUsername(), user.GetPassword(), user.GetBalance()) }
繼承:
在golang中,如果一個struct嵌套了另一個匿名函數體,那么這個結構體可以直接訪問匿名結構體的字段和方法,從而實現了繼承特性。
1)代碼的復用性提高了
2)代碼擴展性和維護性提高了
深入討論:
1)結構體可以使用嵌套匿名結構體所有的字段和方法,即:首字母大小寫的字段、方法,都可以使用;
2)匿名結構體字段訪問可以簡化:b.A.hobby() ==> b.hobby();
3)當結構體和匿名結構體有相同的字段或者方法時,編譯器采用就近訪問原則訪問,如希望訪問匿名結構體和字段和方法,可以通過匿名結構體名來區分;
4)結構體嵌入兩個以上匿名結構體,如兩個匿名結構體有相同的字段和方法(同時結構體本身沒有同名的字段和方法),在訪問時,就必須明確指定匿名結構體名字,否則編譯報錯;
5)如果一個struct嵌套了一個有名結構體,這種模式就是組合,如果是組合關系,那么在訪問組合的結構體的字段或方法時,必須帶上結構體的名字;
6)嵌套匿名函數結構體后,也可以在創建結構體變量時(實例),直接指定各個匿名結構體字段的值;
接口:
interface類型可以定義一組方法,但是這些不需要實現。並且interface不能包含任何變量。到某個自定義類型要使用的時候,在根據具體情況把這些方法寫出來。
語法:
type 接口名 interface {
method1(參數列表) 返回值列表
method2(參數列表) 返回值列表
}
注意事項:
1)接口本身不能創建實例,但是可以指向一個實現了該接口的自定義類型的變量(實例);
2)接口中所有的方法都沒有方法體,即都是沒有實現的方法;
3)在Golang中,一個自定義類型需要將某個接口的所有方法都實現,我們說這個自定義類型實現了該接口;
4)只要是自定義數據類型,就可以實現接口,不僅僅是結構體類型;
5)一個自定義類型可以實現多個接口;
6)Golang接口中不能有任何變量
7)一個接口(比如A接口)可以繼承多個別的接口(比如B,C接口),這時如果要實現A接口,也必須將B,C接口的方法全部實現;
8)interface類型默認是一個指針(引用類型),如果沒有對interface初始化就使用,那么會輸出nil;
9)空接口interface{}沒有任何方法,所以所有類型都實現了空接口,即我們可以把任何一個變量賦給空接口。
接口與繼承:
繼承的價值主要在於:解決代碼的復用性和可維護性。
接口的價值主要在於:設計,設計好各種規范(方法),讓其它自定義類型方法實現這些方法。
接口比繼承更加靈活,繼承是滿足 is - a 的關系,而接口只需要滿足 like - a 的關系。
接口在一定程度上實現代碼解耦。
多態:
變量(實例)具有多種形態,面向對象的第三大特征,通過接口實現,可以按照統一的接口來調用不同的實現。這時接口變量就呈現不同的形態。
類型斷言:
接口是一般類型,不知道具體類型,如果要轉成具體類型,就需要使用類型斷言。
var t float32 var x interface{} x = t y := x.(float32) print(y)
如果在進行斷言時,帶上檢測機制,如果成功就ok,否則也不要報panic
var t float32 = 1.1 var x interface{} x = t if y, ok := x.(float32); ok { fmt.Println("convert success") fmt.Println("y 的類型是 %T 值是 %V", y, y) }else { fmt.Println("convert fail") } fmt.Println("繼續執行...")