個人讀者中應該大部分都是 Java
從業者,不知道寫 Java
這些年是否真的有找到對象?python
沒找到也不要緊,總不能在一棵樹上吊死,咱們也能夠來 Go
這邊看看,說不定會有新發現。編程
開個玩笑,本文會以一個 Javaer
的角度來聊聊 Go
語言中的面向對象。json
<!--more-->編程語言
面向對象這一詞來源於Object Oriented Programming
,也就是你們常說的 OOP
。oop
對於 Go
是否爲面向對象的編程語言,這點也是討論已久;不過咱們能夠先看看官方的說法:學習
其餘的咱們暫且不看,Yes and No.
這個回答就比較微妙了,爲了這篇文章還能寫下去咱們先認爲 Go
是面向對象的。this
面向對象有着三個重要特徵:url
Go
並無 Class
的概念,卻可使用 struct
來達到相似的效果,好比咱們能夠對汽車聲明以下:spa
type Car struct { Name string Price float32 }
與 Java
不一樣的是,struct
中只存儲數據,不能定義行爲,也就是方法。3d
固然也能爲 Car
定義方法,只是寫法略有不一樣:
func (car *Car) Info() { fmt.Printf("%v price: [%v]", car.Name, car.Price) } func main() { car := Car{ Name: "BMW", Price: 100.0, } car.Info() }
在方法名稱前加上 (car *Car)
便能將該方法指定給 Car
,其中的 car
參數能夠理解爲 Java
中的 this
以及 Python
中的 self
,就語義來講我以爲 go
更加簡單一些。
畢竟我見過很多剛學習 Java
的萌新很是不理解 this
的含義與用法。
既然談到結構體了那就不得不聊聊 Go
支持的匿名結構體(雖然和麪向對象沒有太大關係)
func upload(path string) { body, err := ioutil.ReadAll(res.Body) smsRes := struct { Success bool `json:"success"` Code string `json:"code"` Message string `json:"message"` Data struct { URL string `json:"url"` } `json:"data"` RequestID string `json:"RequestId"` }{} err = json.Unmarshal(body, &smsRes) fmt.Printf(smsRes.Message) }
Go
容許咱們在方法內部建立一個匿名的結構體,後續還能直接使用該結構體來獲取數據。
這點在咱們調用外部接口解析響應數據時很是有用,建立一個臨時的結構體也不用額爲維護;同時還能用面向對象的方式獲取數據。
相比於將數據存放在 map
中用字段名獲取要優雅許多。
Go
語言中並無 Java
、C++
這樣的繼承概念,類之間的關係更加扁平簡潔。
各位 Javaer
應該都看過這類圖:
相信大部分新手看到這圖時就已經懵逼,更別說研究各個類之間的關係了。
不過這樣好處也明顯:若是咱們抽象合理,整個系統結構會很好維護和擴展;但前提是咱們能抽象合理。
在 Go
語言中更推薦使用組合的方式來複用數據:
type ElectricCar struct { Car Battery int32 } func main() { xp := ElectricCar{ Car{Name: "xp", Price: 200}, 70, } fmt.Println(xp.Name) }
這樣咱們即可以將公共部分的數據組合到新的 struct
中,並可以直接使用。
面向接口編程的好處這裏就不在贅述了,咱們來看看 Go 是如何實現的:
type ElectricCar struct { Car Battery int32 } type PetrolCar struct { Car Gasoline int32 } //定義一個接口 type RunService interface { Run() } // 實現1 func (car *PetrolCar) Run() { fmt.Printf("%s PetrolCar run \n", car.Name) } // 實現2 func (car *ElectricCar)Run() { fmt.Printf("%s ElectricCar run \n", car.Name) } func Do(run RunService) { run.Run() } func main() { xp := ElectricCar{ Car{Name: "xp", Price: 200}, 70, } petrolCar := PetrolCar{ Car{Name: "BMW", Price: 300}, 50, } Do(&xp) Do(&petrolCar) }
首先定義了一個接口 RunService
;ElectricCar
與 PetrolCar
都實現了該接口。
能夠看到 Go
實現一個接口的方式並非 implement
,而是用結構體聲明一個相同簽名的方法。
這種實現模式被稱爲」鴨子類型「,Python
中的接口也是相似的鴨子類型
。
詳細介紹能夠參考這篇:Python 中的面向接口編程
接口固然也是能夠擴展的,相似於 struct
中的嵌套:
type DiService interface { Di() } //定義一個接口 type RunService interface { DiService Run() }
得益於 Go
的強類型,剛纔的 struct
也得實現 DiService
這個接口才能編譯經過。
到這裏應該是能理解官方所說的 Yes and No.
的含義了;Go
對面向對象的語法不像 Java
那麼嚴苛,甚至整個語言中都找不到 object(對象)
這個關鍵詞;可是利用 Go
裏的其餘特性也是能實現 OOP
的。
是否爲面向對象我以爲並不重要,主要目的是咱們能寫出易擴展好維護的代碼。
例如官方標準庫中就有許多利用接口編程的例子:
因爲公司技術棧如今主要由 Go
爲主,後續也會繼續更新 Go
相關的實戰經驗;若是你也對學習 Go
感興趣那不妨點個關注吧。