## **章面向對象編程**
1) Golang 也支持面向對象編程(OOP),但是和傳統的面向對象編程有區別,并不是純粹的面向對 象語言。所以我們說 Golang 支持面向對象編程特性是比較準確的。
2) Golang 沒有類(class),Go 語言的結構體(struct)和其它編程語言的類(class)有同等的地位,你可 以理解 Golang 是基于 struct 來實現 OOP 特性的。
3) Golang 面向對象編程非常簡潔,去掉了傳統 OOP 語言的繼承、方法重載、構造函數和析構函 數、隱藏的 this 指針等等
4) Golang 仍然有面向對象編程的繼承,封裝和多態的特性,只是實現的方式和其它 OOP 語言不 一樣,比如繼承 :Golang 沒有 extends 關鍵字,繼承是通過匿名字段來實現。
5) Golang 面向對象(OOP)很優雅,OOP 本身就是語言類型系統(type system)的一部分,通過接口 (interface)關聯,耦合性低,也非常靈活。后面同學們會充分體會到這個特點。也就是說在 Golang 中面 向接口編程是非常重要的特性。
**結構體與結構體變量(實例/對象)的關系示意圖**

對上圖的說明
1) 將一類事物的特性提取出來(比如貓類), 形成一個新的數據類型, 就是一個結構體。
2) 通過這個結構體,我們可以創建多個變量(實例/對象)
3) 事物可以貓類,也可以是 Person , Fish 或是某個工具類。

**快速入門\-面向對象的方式(struct)解決養貓問題**

1) 結構體是自定義的數據類型,代表一類事物.
2) 結構體變量(實例)是具體的,實際的,代表一個具體變量
**結構體變量(實例)在內存的布局(重要!)**

**如何聲明結構體**
```
type 結構體名稱 struct {
field1 type
field2 type
}
```
**字段/屬性**
1) 從概念或叫法上看: 結構體字段 \= 屬性 \= field (即授課中,統一叫字段)
2) 字段是結構體的一個組成部分,一般是基本數據類型、數組,也可是引用類型。比如我們前面定 義貓結構體 的 Name string 就是屬性
**注意事項和細節說明**
1) 字段聲明語法同變量,示例:字段名 字段類型
2) 字段的類型可以為:基本類型、數組或引用類型
3) 在創建一個結構體變量后,如果沒有給字段賦值,都對應一個零值(默認值),規則同前面講的 一樣:
布爾類型是 false ,數值是 0 ,字符串是 ""。 數組類型的默認值和它的元素類型相關,比如 score \[3\]int 則為\[0, 0, 0\]
指針,slice,和 map 的零值都是 nil ,即還沒有分配空間。


4) 不同結構體變量的字段是獨立,互不影響,一個結構體變量字段的更改,不影響另外一個, 結構體 是值類型。



#### **創建結構體變量和訪問結構體字段**
方式1-直接聲明
var 結構體名 結構體
方式2-{}
var personPerson=Person{}

方式3-&
案例:varperson\*Person=new(Person)

方式4-{}
案例:varperson\*Person=&Person{}

**說明:**
1)第3種和第4種方式返回的是結構體指針。
2)結構體指針訪問字段的標準方式應該是:(\*結構體指針).字段名,比如(\*person).Name="tom"
3)但go做了一個簡化,也支持結構體指針.字段名,比如person.Name="tom"。更加符合程序員
使用的習慣,go編譯器底層對person.Name做了轉化(\*person).Name。
**struct類型的內存分配機制**






**1)結構體的所有字段在內存中是連續的**
**在下面的代碼中r1中有四個int 在內存中是連續的地址為16進制數那么相差8個數那么就相差8個字節逢8進一 好處是根據地址加減尋找非常快**



2)結構體是用戶單獨定義的類型,和其它類型進行轉換時需要有完全相同的字段(名字、個數和類型)

3)結構體進行type重新定義(相當于取別名),Golang認為是新的數據類型,但是相互間可以強轉

4)struct的每個字段上,可以寫上一個tag,該tag可以通過反射機制獲取,常見的使用場景就是序列化和反序列化。


## **二:方法**
Golang中的方法是作用在指定的數據類型上的(即:和指定的數據類型綁定),因此自定義類型,都可以有方法,而不僅僅是struct。
**方法的聲明和調用**
```
typeAstruct{
Numint
}
func(aA)test(){
fmt.Println(a.Num)
}
對上面的語法的說明
1)func(aA)test(){}表示A結構體有一方法,方法名為test
2)(aA)體現test方法是和A類型綁定的
```

對上面的總結
1)test方法和Person類型綁定
2)test方法只能通過Person類型的變量來調用,而不能直接調用,也不能使用其它類型變量來調用

3)func(pPerson)test(){}...p表示哪個Person變量調用,這個p就是它的副本,這點和函數傳參非常相似
4)p這個名字,有程序員指定,不是固定,比如修改成person也是可以
方法的調用和傳參機制原理:(重要!)
方法的調用和傳參機制和函數基本一樣,不一樣的地方是方法調用時,會將調用方法的變量,當做實參也傳遞給方法。下面我們舉例說明。

說明:
1)在通過一個變量去調用方法時,其調用機制和函數一樣
2)不一樣的地方時,變量調用方法時,該變量本身也會作為一個參數傳遞到方法(如果變量是值類型,則進行值拷貝,如果變量是引用類型,則進行地質拷貝)
**方法的聲明(定義)**
```
func(receviertype)methodName(參數列表)(返回值列表){
方法體
return返回值
}
1)參數列表:表示方法輸入
2)receviertype:表示這個方法和type這個類型進行綁定,或者說該方法作用于type類型
3)receivertype:type可以是結構體,也可以其它的自定義類型
4)receiver:就是type類型的一個變量(實例),比如:Person結構體的一個變量(實例)
5)返回值列表:表示返回的值,可以多個
6)方法主體:表示為了實現某一功能代碼塊
7)return語句不是必須的。
```
**方法的注意事項和細節**
1)結構體類型是值類型,在方法調用中,遵守值類型的傳遞機制,是值拷貝傳遞方式
2)如程序員希望在方法中,修改結構體變量的值,可以通過結構體指針的方式來處理

3)Golang中的方法作用在指定的數據類型上的(即:和指定的數據類型綁定),因此自定義類型,都可以有方法,而不僅僅是struct,比如int,float32等都可以有方法

4)方法的訪問范圍控制的規則,和函數一樣。方法名首字母小寫,只能在本包訪問,方法首字母大寫,可以在本包和其它包訪問。\[講解\]
5)如果一個類型實現了String()這個方法,那么fmt.Println默認會調用這個變量的String()進行輸出

**方法和函數區別**
1)調用方式不一樣
函數的調用方式:函數名(實參列表)
方法的調用方式:變量.方法名(實參列表)
2)對于普通函數,接收者為值類型時,不能將指針類型的數據直接傳遞,反之亦然

3)對于方法(如struct的方法),接收者為值類型時,可以直接用指針類型的變量調用方法,反過來同樣也可以


1)不管調用形式如何,真正決定是值拷貝還是地址拷貝,看這個方法是和哪個類型綁定.
2)如果是和值類型,比如(pPerson),則是值拷貝,如果和指針類型,比如是(p\*Person)則是地址拷貝。
**創建結構體變量時指定字段值**
方式1

方式2
