Golang中匿名組合實現偽繼承的方法

2022-09-24 18:15:12 字數 4247 閱讀 5006

"go語言的物件導向機制與一般語言不同。 它沒有類層次結構, 甚至可以說沒有類; 僅僅通過組合( 而不是繼承) 簡單的物件來構建複雜的物件。" -- 《go語言聖經》

1.匿名組合

1.1 匿名組合定義

golang中組合語法,就是在乙個類中,引入了另乙個類,如

type logger struct

type work struct

type work2 struct

func (logger)info(v ...inte***ce{})

如上邊**所示,work類中定義了乙個logger型別的變數,這種是比較常見的引入方式,姑且在此稱之為非匿名組合,那什麼是匿名組合呢,如其名,就是在組合的過程中,不給名字唄,如**所示:

type logger struct

type work struct

type work2 struct

func (logger) info(v ...inte***ce{})

上邊的**中,work類與work2類均與logger類匿名組合。兩個類唯一不同的是,work2中組合的是指標型別的logger類。

1.2 組合物件初始化

非匿名組合初始化方式

func main()}

var wwk = work}

//...and so on

var wk2 = work2

var wwk2 = work2

//... and so on

}匿名組合初始化

func main()}

var wwk = work}

//... and so on

var wk2 = work2

var wwk2 = work2}

//... and so on

}上邊是匿名組合常見的初始化方式。匿名組合後,被包含類得方法和屬性可以直接被使用,即使是私有變數。

注意事項:

1.匿名組合多個類時,不同的類存在相同的方法,會不會衝突?答案是,不同的類中,不同的方法時不會衝突的,但是在呼叫這個方法時,需要明確是那個類中的方法,如果匿名組合進來的類得方法,與這個類主體中的方法發生衝突,那麼預設情況下,會使用主體類中的方法。

2.匿名組合多個類時,類名相同,會不會衝突?答案是,會。就算包名不同,類名相同,也會衝突。

示例**:

package main

import(

"bufio"

)type reader struct

type work4 struct

上邊**編譯時,會提示reader重複定義 duplicate field reader

原因在於,匿名組合中,沒有給引入的類命名,所以預設採用了類名作為屬性名。如上邊wwk2這個物件在呼叫logger的info方法時,可以採用wwk2.info(「hello」),也可以採用wwk2.logger.info(「hello」).

下邊附上一段完整的演示**,注意會報錯哦,這段**包含了上邊的duplicate field reader錯誤:

package main

import (

"bufio"

"fmt"

)type logger struct

type work struct

type work2 struct

type work3 struct

type reader struct

type work4 struct

func (logger) info(v ...inte***ce{})

func main() }

wk.info("hello: work}")

var wwk = work}

wwk.info("hello: work}")

//... and so on

var wk2 = work2

wk2.info("hello: work2")

var wwk2 = work2}

wwk2.info("hello: work2}")

wwk2.logger.info("hello: wwk2.logger.info")

var wk3 = work3

wk3.log.info("hello: work3")

}3. 結構體嵌入和匿名成員

go語言提供別樣的 結構體嵌入 機制,讓乙個結構體包含另乙個結構體型別的 匿名成員 , 這樣就可以通過簡單的點運算子x.f來訪問匿名成員鏈中巢狀的x.d.e.f成員。

go語言有乙個特性讓我們只宣告乙個成員對應的資料型別而不指名成員的名字; 這類成員就叫匿名成員。 匿名成員的資料型別必須是命名的(而不是匿名的)型別或指向乙個命名的型別的指標。

type circle struct

type wheel struct

由於有了匿名嵌入的特性, 我們可以直接訪問內嵌型別的成員變數而不需要給出完整的路徑:

var w wheel

w.x = 8 // 等價於 w.circle.point.x = 8

w.y = 8 // 等價於 w.circle.point.y = 8

w.radius = 5 // 等價於 w.circle.radius = 5

w.spokes = 20

同樣的規則,內嵌型別的方法也會提公升為外部型別的方法。

3.1 匿名衝突(duplicate field)

匿名成員也有乙個隱式的名字,以其型別名稱(去掉包名部分)作為成員變數的名字。 因此不能同一級同時包含兩個型別相同的匿名成員, 這會導致名字衝突。

type logger struct

type myjob struct

4. 匿名組合不是繼承

4.1 程式設計客棧方法的接受者沒變

當我們嵌入乙個型別,這個型別的方法就變成了外部型別的方法,但是當它被呼叫時,方法的接受者是內部型別(嵌入型別),而非外部型別。— effective go

type job struct

func (job *job)start()

上面這個job例子,即使組合後呼叫的方式變成了job.log(...),但log函式的接收者仍然是 log.logger指標,因此在log中也不可能訪問到job的其他成員方法和變數。

4.1 內嵌型別不是基類

如果讀者對基於 類 來實現的物件導向語言比較熟悉的話, 可能會傾向於將 內嵌型別 看作乙個基類, 而 外部型別 看作其子類或者繼承類, 或者將 外部型別 看作 "is a" 內嵌型別 。 但這樣理解是錯誤的。

type point struct

type coloredpoint struct

func (p point) distance(q sdtemhpoint) float64

請注意上面例子中對distance方法的呼叫。 distance有乙個引數是point型別, 但q並不是乙個point類, 所以儘管q有著point這個內嵌型別, 我們也必須要顯式地選擇它。 嘗試直接傳q的話你會看到錯誤:

red := color.rgba

blue := color.rgba

var p = coloredpoint, red}

var q = coloredpoint, blue}

fmt.println(p.distance(q.point)) // "5"

p.distance(q) // compile error: cannot use q (coloredpoint) as point

乙個coloredpoint並不是乙個point, 但coloredpoint "has a" point, 並且它有從point類裡引入的 distance方法。

實際上,從實現的角度來考慮問題, 內嵌欄位會指導編譯器去生成額外的包裝方法來委託已經宣告好的方法, 和下面的形式是等價的:

func (p coloredpoint) distance(q point) float64

當point.distance被以上編譯器生成的包裝方法呼叫時, 它的接收程式設計客棧器值是p.point, 而不是p。

4.3 匿名衝突(duplicate field) 和隱式名字

匿名成員也程式設計客棧有乙個隱式的名字,以其型別名稱(去掉包名部分)作為成員變數的名字。 因此不能同一級同時包含兩個型別相同的匿名成員, 這會導致名字衝突。

type logger struct

type myjob struct

以下兩點都間接說明匿名組合不是繼承:

本文標題: golang中匿名組合實現偽繼承的方法

本文位址:

golang匿名組合

一般情況下,定義結構體的時候是欄位名和其型別一一對應,實際上go支援只提供型別而不寫欄位名的方法,也就是匿名字段,也稱為嵌入式字段 當匿名欄位也是乙個結構體的時候,那麼這個結構體所擁有的全部欄位都被隱式的引入了當前定義的這個結構體 實現 復用 type person struct type stud...

golang中的匿名組合

確切地說,go語言也提供了繼承,但是採用了組合的文法,所以我們將其稱為匿名組合 type base struct func base base bar type foo struct base func foo foo bar foo.base.bar 以上 定義了乙個base類 實現了foo 和b...

golang 使用組合的方式實現繼承

火頭陀 關注 golang並非完全物件導向的程式語言,為了實現物件導向的繼承這一神奇的功能,golang允許struct間使用匿名引入的方式實現物件屬性方法的組合 package main import fmt type people struct type people2 struct func ...