golang | Go語言入門教程——結構體初始化與繼承

本文始發於我的公衆號:TechFlow,原創不易,求個關注golang


今天是golang專題第10篇文章,咱們繼續來看golang當中的面向對象部分。web

在上一篇文章當中咱們一塊兒學習了怎麼建立一個結構體,以及怎麼給結構體定義函數,還有函數接收者的使用。今天咱們來學習一下結構體自己的一些使用方法。編輯器

初始化

在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關鍵字,咱們更經常使用的是經過結構體名稱加上花括號的方式來進行初始化。ui

若是咱們再也不花括號當中填寫參數的話,那麼一樣會獲得一個填充了零值的結構體。結構體當中的全部屬性都會被賦予這個類型對應的零值。url

type Point struct {
 x int  y int }  func main() {  p := Point{}  fmt.Print(p) } 複製代碼

若是咱們想要初始化一個結構體的指針,咱們只須要在結構體名稱以前加上取地址符&便可。因此建立一個結構體指針能夠這樣:spa

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 排版

相關文章
相關標籤/搜索