1. 程式人生 > >Golang的面向物件程式設計【結構體、方法、繼承、介面】

Golang的面向物件程式設計【結構體、方法、繼承、介面】

Golang也支援面向物件程式設計。但與以前學過傳統的面向物件程式語言有區別。
1)Golang沒有類class,Go語言的結構體struct和類class有相似的特性。
2)Golang中不存在繼承,方法過載,建構函式,解構函式,隱藏和this指標。
3)Golang有繼承,封裝,多型的特性,但是實現方法與傳統OOP語言不同。

1. 結構體struct

type 識別符號 struct{
…field type
}

type Student struct {
…Name string // 欄位 屬性
…Age int
…Score float32
}

結構體的欄位型別可以是:基本型別、陣列、引用型別。在建立一個結構體變數時,如果沒有進行欄位賦值,則對應一個預設值。
其中,指標、slice、map的預設值是nil,沒有分配空間,所以如果要使用,需要先進行make。

1.1 結構體例項記憶體佈局

在這裡插入圖片描述
注意:結構體型別屬於值型別。

1.2 結構體例項化


type Student struct {
…Name string // 欄位 屬性
…Age int
…Score float32
}

1)直接宣告

var s1 Student

2)結構體{}

var s2 Student = Student{ “tom” ,12, 98}
// s2 = Student{ “tom” ,12, 98}

3)new函式

var s3 *Student = new(Student)
在這裡插入圖片描述

4)引用地址

var s4 *Student = &Student{ }
// var s4 *Student = &Student{“marry”, 27 ,88}

1.3 結構體使用注意事項

1)結構體中的所有欄位在記憶體中連續的。
2)結構體是使用者自定義型別,若要進行型別轉換,需要具有相同的欄位,包括名字,個數和型別。
在這裡插入圖片描述
3)結構體進行type重新定義,相當於取別名。兩個型別是不相同的資料型別,不能直接賦值,可以通過強制型別轉換。
在這裡插入圖片描述
4)在結構體每個欄位是可以寫tag。該 可以通過反射機制獲取,常見的使用場景就是序列化與反序列化。
在處理json格式字串的時候,經常會看到宣告struct結構的時候,屬性的右側還有小米點括起來的內容。形如

type User struct {
UserId int json:"user_id" bson:"user_id"


UserName string json:"user_name" bson:"user_name"
}

在這裡插入圖片描述
在這裡插入圖片描述

2. 方法

相當於其他OOP語言的類的類函式,在Golang中,方法是作用於指定的資料型別上。自定義型別和基本型別都可以有方法。

func (recevier type) mathodName (引數列表) (返回值列表){
…方法體
…return 返回值
}

type A struct{
…Num int
}
//定義了一個結構體A的方法
func (a A)test(){
…fmt.Println(a.Num)
}

方法的注意事項和細節
1)結構體型別是值型別,在方法呼叫中,也遵守值拷貝傳遞引數。
2)如果需要修改結構體變數,可以通過結構體指標的方式來進行引數傳遞。
在這裡插入圖片描述
3)Golang中方法的作用不僅是結構體的自定義型別,基本資料型別也可以有自己的方法。
在這裡插入圖片描述
4)方法的訪問也有類似於欄位的許可權,即方法名首字母小寫,就只能在本包中訪問,首字母大寫,就可以匯出在其他包中呼叫。
5)如果一個型別實現了String()犯法,那麼對於fmt.Println()函式預設會呼叫這個變數的String()進行輸出。
在這裡插入圖片描述
在這裡插入圖片描述

3. Golang的三大特性:封裝、繼承、多型

3.1 封裝

封裝就是把抽象的欄位和對欄位的操作封裝在一起,資料被保護在內部,程式的其他包只有通過被授權的操作方法,才能對欄位進行操作。
在Golang中封裝的實現比較簡單
1)將結構體、欄位的首字母小寫。
在這裡插入圖片描述
2)給結構體提供一個工廠模式的函式(類似於建構函式),首字母大寫,可被訪問。
在這裡插入圖片描述
3)提供一個Set() 函式方法,對欄位進行修改。
在這裡插入圖片描述
4)提供一個Get() 函式方法,用於獲取欄位。
在這裡插入圖片描述

3.2 繼承

在這裡插入圖片描述

type Goods struct{
…Name string
…Price int
}
type Book struct{
Goods //繼承–巢狀匿名結構體
…Writer string
}

注意:
1)結構體可以使用巢狀匿名結構體的所有欄位和方法。
2)當結構體與匿名結構體有相同欄位或者方法時,編譯器會採用就近訪問原則
3)當結構體中有多個匿名結構體,且匿名結構體具有相同的欄位和方法時,必須指定匿名結構體名字,否則編譯會報錯。
4)如果結構體中巢狀有名的結構體變數,這種模式是組合。訪問欄位和方法時,必須使用巢狀結構體名。

type Book struct{
g Goods //組合–巢狀有名結構體
…Writer string
}

5)巢狀結構體之後,在建立變數時,可以直接指定匿名結構體欄位的值。

b Book{
…Goods{ “1Q84” , 103},
…Wtiter : 東野圭吾,
}

  • 多繼承
    一個結構體嵌套了多個匿名結構體,那麼該結構體可以直接訪問巢狀的匿名結構體的欄位 和方法,從而實現了多重繼承。

3.3 多型

多型是通過介面來實現的。

3.3.1 介面

簡單的介面模擬:
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
Phone,Camera實現了Usb介面的方法,所以phone,Camera就實現了介面的方法。在這裡插入圖片描述

  • 基本語法
    interface型別定義一組方法啊,但不需要實現,而且interface中不能包含任何變數。

type 介面名 intrface {
…方法名1(引數列表)(返回值列表)
…方法名2(引數列表)(返回值列表)
}
介面中的所有方法都沒有方法體。

  • 介面的實現
    自定義型別實現介面,需要實現介面中宣告的所有方法
  • 注意事項與細節
    1)介面不能例項化(類似於C++中的抽象類),可以指向一個實現了該介面的自定義型別的變數。
    在這裡插入圖片描述
    2)只要是自定義資料型別,就可以實現介面,不僅僅是結構體型別。
    在這裡插入圖片描述
    3)一個自定義型別可以實現多個介面。
    4)介面之間可以實現繼承,利用巢狀匿名介面。此時,自定義型別要實現該介面,必須實現該介面所繼承的的介面的方法和自己的方法。即A介面繼承B,C介面,則自定義型別需要實現A,B,C三個介面的所有方法。
    5)interface型別預設是一個指標(引用型別),如果沒有對interface初始化,則其為nil。
    6)空介面type T interface{}沒有任何方法,所有的型別都實現了該空介面,也就可以將任何變數賦給空介面。
  • 介面與繼承間的區別:
    1)繼承的價值在於解決程式碼的複用性和可維護性;介面的價值在於設計出各規範,讓自定義型別去實現。
    2)介面比繼承更加靈活,介面是like-a的關係,繼承是is-a的關係。
    3)介面在一定程度上實現程式碼的解耦。

3.3.2 多型

介面可以體現多型的特徵。
1)多型引數
2)多型陣列
在這裡插入圖片描述

4. 型別斷言

由於介面是一般型別,不知道具體的資料型別,如果需要轉成具體型別,就需要使用型別斷言,如下:
在這裡插入圖片描述
1)在進行型別斷言時,如果型別不匹配,就會崩潰panic,所以在使用的時候確保原來的空介面就是要轉的資料型別。
2)進行斷言時帶檢查機制,如果成功就ok,如果失敗不要崩潰報panic。
在這裡插入圖片描述