Go 語言基礎系列(七):面向對象編程之結構體

階段小結

通過前面的學習,我們對常量、變量、運算符,流程控制,容器,函數以及包等概念有了基本的理解。並且瞭解了這些概念的一種協作關係:常量和變量都是數據的一種載體,數據通過不同的運算符參與運算時,對計算的流程進行一定程度的控制便是流程控制,並且對於較多的數據通過內置容器進行存儲,然後通過對以上的所有概念進行整合,通過函數完成某一特定的功能。相同類型的函數在同一文件中進行呈現,最後對越來越多的文件通過的方式對代碼進行最有效的管理(大家可以試着回想一下我們前面學習的概念, 部分遺忘的話可以再回顧一下)。

以上是我們接觸和學習一種新高級編程語言的較爲通用的一套方式,這樣的話可以對編程語言的整體進行一個很好的把握。那麼在此基礎之上,我們深入語言要進一步學習語言的思想、特性及功能實現等等。所以,我們以 Golang 爲例,從本篇開始將對語言自身的特點(也有可能是區別於其他語言獨有的特點)進行學習。

本篇以及下一篇文章我們學習 Golang 的面向對象編程的思想,分別介紹結構體和接口。首先,請大家記住一句話:Golang 語言是通過結構體和接口來實現面向對象編程的思想。因爲對於一種 “思想”,需要我們在實踐的過程中不斷的學習和領會,不同的階段,不同的經驗積累,都會有不同的新的感悟。

這裏,我們對面向過程編程和麪向對象編程兩種思想進行非常簡短的介紹,大家先有一個基本的概念,之後我們會寫一篇軟件編程的發展史的文章,在裏面再更進一步的說明,但是,還是強烈建議大家:實踐再實踐,實踐中思考,不斷的去領會

首先,可以說,對於面向過程和麪向對象兩種編程方式,沒有哪一種更好,都是不同時期的產物。面向過程編程方式是先於面向對象編程方式出現的,在最初的軟件開發中,主要從業務的具體過程實現出發。過程實現會導致代碼的複用性差,複用差的代碼也難以擴展,並且複用性差會導致更多的代碼重複,這樣的話代碼的維護性就會降低,我們知道軟件的穩定性是最重要的,但是早期的軟件工程較小,這些影響並不會成爲主要因素,而且由於沒有太多的實例化調用(此爲面向對象編程裏的概念),所以性能還更好。但是隨着軟件編程的不斷髮展,軟件工程越來越龐大,軟件的可維護性,可複用性和可擴展性變得越來越重要,所以出現了面向對象的編程方式。

面向對象編程的三個特點:封裝,繼承和多態。我們在後面的介紹中會展開介紹

思維邏輯圖如下:

下面我們從以上四個方面對 **結構體 **進行相應的介紹

**   結構體的聲明  **

結構體是對現實中存在的實體對象的一次抽象,也是一次封裝 (面向對象)

結構體由成員變量構成,而成員變量是對現實對象屬性的不同表示

以開發者爲例,具有如下屬性:姓名,性別,年齡,工號,部門等

結構體聲明通過關鍵字 type 和 struct 實現,標準格式如下:

type 結構體名字 struct {

**        成員變量 1   類型 1
**

**        成員變量 2   類型 2
**

**        成員變量 3   類型 3
**

**        ...    
**

}

注:1)同一結構體,成員變量名不同相同

       2)相同類型的成員變量可以通過如下形式:成員變量 1,成員變量 2   類型

 3)同一包內,不能結構體同名

4)不同的包,如希望結構體或者成員變量可導出,可通過首字母大寫的方式實現

**示例:**聲明一個 developer 結構體

**   結構體實例化及初始化  **

01

** 普通結構體的實例化 **

結構體的使用需要先聲明後實例化,然後才能進行使用。實例化的方式有三種:標準實例化,取地址實例化和 new 函數實例化

1)標準實例化:標準實例化是通過 var 關鍵字完成,格式如下: 

var   結構體實例名稱   結構體類型名

例如,聲明並實例化一個名爲 developer1 的 developer 結構體類型

2)取地址實例化:通過獲取指針地址符號 & 加 結構體類型名完成,格式如下: 

結構體實例名 := & 結構體類型名 {}

同樣,聲明並實例化一個名爲 developer1 的 developer 結構體類型

結果如下:

2)new 函數實例化:返回結構體的指針類型,格式如下:

結構體實例名 := new(結構體類型名)

同樣,聲明並實例化一個名爲 developer1 的 developer 結構體類型

結果如下:

02

** 普通結構體初始化 **

結構體初始化即是對結構體中的成員變量進行賦值,主要有三種形式:1)聲明後通過  **點. **訪問成員變量進行賦值;2)聲明的同時以 map 初始化的方式初始化;3)聲明的同時按成員變量聲明順序按序賦值;

1)聲明後通過 .****訪問成員變量進行賦值

結果如下:

2)聲明的同時以 map 初始化的方式初始化

結果如下:

3)聲明的同時按成員變量聲明順序按序賦值

03

** 匿名結構體實例化及初始化 **

匿名結構體的初始化不需要 type 關鍵字,也不需要結構體類型名。格式如下:

**結構體實例名 := struct { **

**    成員變量 1  類型 1
**

**    成員變量 2  類型 2
**

**    成員變量 3  類型 3**

**    ...
**

} {

**    成員變量 1:變量值 1,
**

**    成員變量 2:變量值 2,**

**    成員變量 3:變量值 3,**

**    ...    
**

}

示例:

結果如下:

解釋:示例中成員變量的值的初始化爲可選的,我們可以在實例化時先不進行初始化,後面可以通過 **點 . 訪問成員變量進行賦值,**或者直接進行初始化

**   結構體方法  **

首先,在 Golang 語言中,方法和函數兩個概念是不相同的,前面的文章中我們已經介紹過函數的概念,那麼方法是什麼呢?方法是具有接收者的函數。

接收者可分爲:指針變量接收者和值變量接收者

**

01

** 指針變量接收**

**

指針變量接收者,**帶 ***

func (結構體接收者名 * 結構體類型) 方法名(入參){

**        方法體
**

}

結果如下:

**02
**

**** 值變量接收****

值變量接收者,**不****帶 ***

func (結構體接收者名 結構體類型) 方法名(入參){

**        方法體
**

}

結果如下:

總結:值類型接收者不可以修改結構體成員變量,如需要修改結構體成員變量,應使用指針類型接收者

**   結構體內嵌  **

面向對象編程思想的第二特點:繼承。在 Golang 中,結構體內嵌體現了面向對象編程的 “繼承” 特點

01

** 內嵌普通結構體 **

格式如下:

type  結構體 1 名 struct {

**    成員變量 1 類型 1
**

}

type 結構體 2 名 struct {

**    結構體 1 名**

**    成員變量 2 類型 2
**

}

示例:developer 可以分屬於不同的國家

結果如下:

分析:結構體 developerInDeferentCountry 結構體內嵌了 developer 結構體,並且擁有了結構體 developer 的方法

02

** 內嵌匿名結構體 **

對於內嵌匿名結構體,格式如下:

type  結構體 1 名 struct  {

**    結構體 2 名 struct {**

**        成員變量 類型
**

**    } **

**    成員變量 類型
**

}

但是,在內嵌匿名結構體中,對結構體初始化時,初始化匿名結構體,仍需再次聲明結構體,如下示例:

分析:示例中,main 函數中對結構體初始化時,由於是匿名結構體內嵌,所以需再次聲明結構體

到此關於 Golang 面向對象編程之結構體的分享就結束了~

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Na4Y6Wg5-GzIPMENERy6jA