本文始發於個人公眾號:TechFlow,原創不易,求個關注
今天是golang專題第10篇文章,我們繼續來看golang當中的面向對象部分。
在上一篇文章當中我們一起學習了怎么創建一個結構體,以及怎么給結構體定義函數,還有函數接收者的使用。今天我們來學習一下結構體本身的一些使用方法。
初始化
在golang當中結構體初始化的方法有四種。
new關鍵字
我們可以通過new關鍵字來創建一個結構體的實例,這種方法和其他語言比較類似,這樣會得到一個空結構體指針,當中所有的字段全部填充它類型對應的零值。比如int就對應0,float對應0.0,如果是其他結構體則對應nil。
type Point struct {
x int y int } func main() { var p *Point = new(Point) fmt.Print(p) }
從這段代碼當中我們可以看到,new函數返回的是一個結構體指針,而不是結構體的值。一般我們很少用new關鍵字,而是直接通過結構體加花括號的方式來初始化。
結構體名稱
相比於使用new關鍵字,我們更常用的是通過結構體名稱加上花括號的方式來進行初始化。
如果我們不再花括號當中填寫參數的話,那么同樣會得到一個填充了零值的結構體。結構體當中的所有屬性都會被賦予這個類型對應的零值。
type Point struct {
x int y int } func main() { p := Point{} fmt.Print(p) }
如果我們想要初始化一個結構體的指針,我們只需要在結構體名稱之前加上取地址符&即可。所以創建一個結構體指針可以這樣:
func main() {
p := &Point{} fmt.Print(p) }
golang當中取地址符和聲明指針的關鍵字和C語言是一樣的,對於熟悉C語言的同學來說,這應該並不困難。
我們在花括號當中填充參數,這些參數會按照順序填充到結構體的屬性當中。為了防止混淆,我們也可以在值之前加上它對應的屬性名稱。
func main() {
p := &Point{0, 0} k := &Point{x: 0, y: 10} fmt.Print(p) }
繼承
很多人不喜歡golang的主要原因就是覺得golang閹割了面向對象的很多功能之后,導致開發的時候束手束腳,總覺得不太方便。其中為人詬病得比較厲害的就是繼承,覺得golang當中沒有繼承,寫有依賴的結構體的時候非常蛋疼。
我之前一度也這么覺得,最近仔細研究了其中的道道之后,發現我錯了,golang當中也是有繼承的,不過它實現的方式和我們一般理解上的不太一樣,有一些出其不意。所以我們拿正統的眼光去看它總會覺得它不倫不類,哪里不太對勁。這種感覺有點像是武俠小說里名門正派看旁門左派的感覺,但旁門左派並不代表就不行,也有能打的。
在我們正常的映像當中,我們實現繼承就應該是標明當前這個類的父類是哪個類,這樣底層編譯器自動將父類的屬性和方法都拷貝一份到子類當中來。加上private、public等關鍵詞束縛,來控制一下什么方法和屬性可以被繼承什么不可以就完美了。
我們用Python舉個例子,Python當中對於繼承的定義已經非常簡潔了,實現起來大概是這樣的:
class A:
pass class B(A): pass
直接在類名的后面就加上繼承的信息,實際上絕大多數主流語言也都是這么干的。但golang不是,它做了一件什么事呢?它將父類作為變量定義在了子類的里面,嚴格說起來這已經不是繼承了,算是一種奇怪的組合,但它起到的功能類似於繼承。
我光說理解起來很累,我們來看個例子,比如我們當下有一個父類(結構體),它有兩個結構體方法:
type Father struct {
Name string } func(entity Father) Hello() {...} func(entity Father) World() {...}
現在我們要創建一個它的子類,需要把Father這個結構體填進去,變成其中一個成員變量。
type Child struct {
Father ... }
那有了這么一個看起來很奇怪的子類之后,我們怎么調用父類的方法呢?
答案是直接調用。
child := Child{}
child.Hello()
按照我們的理解,由於父類是子類當中的一個成員,所以我們想要調用父類的方法,應該寫成child.Father.Hello()才對。但實際上golang替我們做了相關的優化,我們直接調用方法,也可以找到父類當中的方法。
如果我們要改寫父類的方法也不困難,我們可以這樣操作:
func (entity Child) World() {
entity.Father.World() ... }
如此,父類當中的World方法就被Child改寫了,這樣就完成了繼承當中對父類函數的改寫。
總結
到這里,關於golang當中結構體初始化與繼承的介紹就結束了。不知道大家看完這篇有什么樣的感受,我最大的感覺是好像沒有第一次看到它的時候那么難以接受了XD。
據說這個設計和C++當中的虛基類的概念非常接近,但是虛基類非常難以理解(比如我就沒能理解),以至於許多C++工程師會自動忽略它的存在。相比之下,golang的這種設計要容易理解得多。雖然看起來麻煩,但是理解起來也並不困難。
今天的文章到這里就結束了,如果喜歡本文的話,請來一波素質三連,給我一點支持吧(關注、轉發、點贊)。
本文使用 mdnice 排版