這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
前言: 本文是學習<<go語言程式設計>> -- 清華大學出版社(王鵬 編著) 的2014年1月第一版 做的一些筆記 , 如有侵權, 請告知筆者, 將在24小時內刪除, 轉載請註明出處!
1. 對象
- 任意簡單的內建資料類型
- 任意複雜的結構體
- 表示具體的事物 / 抽象的規則 / 計劃 / 事件 等.
2. 對象的狀態
- 用數值來描述, 如長方體的長和寬等.
3. 對象的操作
- 用於改變對象的狀態, 操作就是對象的行為.
- GO語言中稱為Method(方法), Method 就是在 函數(function) 前面增加了一個接收者(Receiver)對象. 將操作和對象關聯起來了.
- 定義: func (recv receiver_type) methodName(args)(rets){} Receiver 可以是: 內建類型/自訂類型/結構體/指標類型
- 多個Method可以同名, 只要接收者不同, 就是不同的Method.(類似於重載吧)
- Method可以訪問接收者的欄位, 而不需要將欄位作為參數傳入Method, 就像在struct中訪問欄位一樣.
- 普通類型作為Receiver,是值傳遞; 指標類型作為Receiver, 將傳遞引用.
package mainimport ( "fmt" "math")type rect struct { width int height int}type circle struct { radius float32}func (recv rect) area() int { return recv.width * recv.height}func (recv circle) area() float32 { return recv.radius * recv.radius * math.Pi}func main() { r1 := rect{4, 3} r2 := rect{30, 15} fmt.Println(r1.area(), r2.area()) c := circle{5} fmt.Println(c.area())}
- Receiver
- 匿名Receiver, 省略了receiver的名字(類型沒有省,所以可以判斷), 此時不能定義同名的方法(應該是會造成無法將操作和對象綁定).
- Method 繼承
- go中可以通過匿名欄位實現欄位繼承; 如果匿名欄位實現了一個Method(或者說是這個Method的Receiver), 那麼包含這個匿名欄位的struct對象也能調用該Method.
- 可以重寫繼承的方法, 對象會像處理匿名欄位一樣, 優先處理外部同名Method.
4. 介面(Interface)
- 一組Method的組合, 可以通過Interface來定義對象的一組行為, 如果某個對象實現了某個介面的所有方法, 那麼它就實現了該介面. 無須顯式在該類型上添加介面說明.
- 習慣以 "er" 結尾, 如: Printer, Reader, Writer.
- 一個Interface中包含的Method不宜過多, 一般 0 - 3個
- Interface可以被任意的對象實現, 一個對象也可以實現多個 Interface.
- 介面組合
- 類似類型的匿名組合(如結構體, Method) ,介面也可以組合: 將一個/多個介面匿名嵌入另外一個介面中 , 就組合了介面.
type SpeakListener interface{ Speaker // Speaker為一個匿名介面 Learner // Learner 為一個匿名介面}
- 空介面 : 任何資料類型都預設實現了空介面. interface {}
- 可以用來定義任意類型的參數和傳回值. (有點兒像是void 和 void* 的用處吧) : 1. func f1(a interface{}){} 2. func f2(a ... interface{}){}
- 執行機制和賦值
- 介面是參考型別.(如何理解呢? )
- 介面是可以被執行個體化的類型, 當定義一個介面類型變數時, 系統會為其分配記憶體, 並將賦給它的對象賦值到這個記憶體地區.
- 介面對象(由 Itab指標和data指標組成)
struct Iface{ // C語言中的表示 Itab * tab; void * data;};
- Itab : 依據data類型建立, 儲存了介面動態調用的中繼資料資訊, 其中包括data類型所有符合介面簽名的方法地址清單. 使用介面對象調用方法時就從Itab中尋找對應的方法, 並將 *data 作為Receiver參數傳遞給該方法.
- 編譯器在構建 Itab時, 區分T 和 * T 方法集, 病從中擷取介面實現方法的地址指標, 介面調用不會做Receiver自動轉換, 目標方法必須在介面實現的方法集中. 介面方法集規則:
- T 僅僅擁有T類型的方法集, 而 *T擁有(T+*T)方法集
- 基於T實現方法, 表示同事實現了interface(T) 和interface(*T) 介面
- 基於(*T)實現方法, 就只能是對 interface(*T)實現介面
- 介面的定義與賦值
- 定義了一個interface的變數, 那麼變數裡面可以儲存實現了這個interface的任意類型的對象.
- 多個對象同時實現了這個介面的話, 那麼可以用這個介面作為類型, 定義一個slice, 那麼就可以寫出比較少的代碼. ix = make([]Speaker,3)
- 匿名欄位方法和介面轉換
- 當介面類型是struct時, 這些struct可能有匿名欄位, 而為這些匿名欄位定義的方法也會被介面所繼承.
- 介面之間可以相互包含. == > 超級(範圍大) + 子集(範圍小)