一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Golang - Golang中匿名組合實現偽繼承的方法

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

2020-05-19 09:30ggq89 Golang

這篇文章主要介紹了Golang中匿名組合實現偽繼承的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

1.匿名組合

1.1 匿名組合定義

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

?
1
2
3
4
5
6
7
8
9
10
11
type Logger struct{
}
type Work struct{
  log Logger
}
type Work2 struct{
  log *Logger
}
 
func (Logger)Info(v ...interface{}){
}

如上邊代碼所示,Work類中定義了一個Logger類型的變量,這種是比較常見的引入方式,姑且在此稱之為非匿名組合,那什么是匿名組合呢,如其名,就是在組合的過程中,不給名字唄,如代碼所示:

?
1
2
3
4
5
6
7
8
9
10
11
type Logger struct {
}
type Work struct {
  Logger
}
type Work2 struct {
  *Logger
}
 
func (Logger) Info(v ...interface{}) {
}

上邊的代碼中,Work類與Work2類均與Logger類匿名組合。兩個類唯一不同的是,Work2中組合的是指針類型的Logger類。

1.2 組合對象初始化

非匿名組合初始化方式

?
1
2
3
4
5
6
7
8
9
func main(){
  var wk = Work{log:Logger{}}
  var wwk = Work{Logger{}}
  //...and so on
 
  var wk2 = Work2{log:new(Logger)}
  var wwk2 = Work2{new(Logger)}
  //... and so on
}

匿名組合初始化

?
1
2
3
4
5
6
7
8
func main(){
  var wk = Work{Logger{}}
  var wwk = Work{Logger:Logger{}}
  //... and so on
  var wk2 = Work2{new(Logger)}
  var wwk2 = Work2{Logger:&Logger{}}
  //... and so on
}

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

注意事項:

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

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

示例代碼:

?
1
2
3
4
5
6
7
8
9
10
package main
import(
  "bufio"
)
type Reader struct {
}
type Work4 struct {
  Reader
  bufio.Reader
}

上邊代碼編譯時,會提示Reader重復定義 duplicate field Reader

原因在于,匿名組合中,沒有給引入的類命名,所以默認采用了類名作為屬性名。如上邊wwk2這個對象在調用Logger的Info方法時,可以采用wwk2.Info(“hello”),也可以采用wwk2.Logger.Info(“hello”).

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package main
 
import (
  "bufio"
  "fmt"
)
 
type Logger struct {
}
 
type Work struct {
  Logger
}
 
type Work2 struct {
  *Logger
}
type Work3 struct {
  log *Logger
}
 
type Reader struct {
}
type Work4 struct {
  Reader
  bufio.Reader
}
 
func (Logger) Info(v ...interface{}) {
  fmt.Println(v...)
}
 
func main() {
  var wk = Work{Logger{}}
  wk.Info("hello: Work{Logger{}}")
  var wwk = Work{Logger: Logger{}}
  wwk.Info("hello: Work{Logger: Logger{}}")
  //... and so on
  var wk2 = Work2{new(Logger)}
  wk2.Info("hello: Work2{new(Logger)}")
  var wwk2 = Work2{Logger: &Logger{}}
  wwk2.Info("hello: Work2{Logger: &Logger{}}")
  wwk2.Logger.Info("hello: wwk2.Logger.Info")
 
  var wk3 = Work3{new(Logger)}
  wk3.log.Info("hello: Work3{new(Logger)}")
}

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

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

Go語言有一個特性讓我們只聲明一個成員對應的數據類型而不指名成員的名字; 這類成員就叫匿名成員。 匿名成員的數據類型必須是命名的(而不是匿名的)類型或指向一個命名的類型的指針。

?
1
2
3
4
5
6
7
8
9
type Circle struct {
 Point
 Radius int
}
 
type Wheel struct {
 Circle
 Spokes int
}

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

?
1
2
3
4
5
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)

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

?
1
2
3
4
5
6
7
8
9
type Logger struct {
  Level int
}
 
type MyJob struct {
  *Logger
  Name string
  *log.Logger // duplicate field Logger
}

4. 匿名組合不是繼承

4.1 方法的接受者沒變

當我們嵌入一個類型,這個類型的方法就變成了外部類型的方法,但是當它被調用時,方法的接受者是內部類型(嵌入類型),而非外部類型。— Effective Go

?
1
2
3
4
5
6
7
8
9
10
type Job struct {
 Command string
 *log.Logger
}
 
func (job *Job)Start() {
 job.Log("starting now...")
 ... // 做一些事情
 job.Log("started.")
}

上面這個Job例子,即使組合后調用的方式變成了job.Log(...),但Log函數的接收者仍然是 log.Logger指針,因此在Log中也不可能訪問到job的其他成員方法和變量。

4.1 內嵌類型不是基類

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

?
1
2
3
4
5
6
7
8
9
10
11
12
type Point struct{ X, Y float64 }
 
type ColoredPoint struct {
 Point
 Color color.RGBA
}
 
func (p Point) Distance(q Point) float64 {
 dX := q.X - p.X
 dY := q.Y - p.Y
 return math.Sqrt(dX*dX + dY*dY)
}

請注意上面例子中對Distance方法的調用。 Distance有一個參數是Point類型, 但q并不是一個Point類, 所以盡管q有著Point這個內嵌類型, 我們也必須要顯式地選擇它。 嘗試直接傳q的話你會看到錯誤:

?
1
2
3
4
5
6
7
red := color.RGBA{255, 0, 0, 255}
blue := color.RGBA{0, 0, 255, 255}
var p = ColoredPoint{Point{1, 1}, red}
var q = ColoredPoint{Point{5, 4}, 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方法。

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

?
1
2
3
func (p ColoredPoint) Distance(q Point) float64 {
 return p.Point.Distance(q)
}

當Point.Distance被以上編譯器生成的包裝方法調用時, 它的接收器值是p.Point, 而不是p。

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

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

?
1
2
3
4
5
6
7
8
9
type Logger struct {
Level int
}
 
type MyJob struct {
*Logger
Name string
*log.Logger // duplicate field Logger
}

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

  • 匿名成員有隱式的名字
  • 匿名可能沖突(duplicate field)

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://studygolang.com/articles/14448

延伸 · 閱讀

精彩推薦
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • Golanggolang json.Marshal 特殊html字符被轉義的解決方法

    golang json.Marshal 特殊html字符被轉義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉義的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
  • GolangGolang中Bit數組的實現方式

    Golang中Bit數組的實現方式

    這篇文章主要介紹了Golang中Bit數組的實現方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨尊11682021-06-09
  • Golanggolang如何使用struct的tag屬性的詳細介紹

    golang如何使用struct的tag屬性的詳細介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細介紹,從例子說起,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看...

    Go語言中文網11352020-05-21
  • Golanggo日志系統logrus顯示文件和行號的操作

    go日志系統logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • Golanggolang的httpserver優雅重啟方法詳解

    golang的httpserver優雅重啟方法詳解

    這篇文章主要給大家介紹了關于golang的httpserver優雅重啟的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    helight2992020-05-14
  • GolangGolang通脈之數據類型詳情

    Golang通脈之數據類型詳情

    這篇文章主要介紹了Golang通脈之數據類型,在編程語言中標識符就是定義的具有某種意義的詞,比如變量名、常量名、函數名等等,Go語言中標識符允許由...

    4272021-11-24
主站蜘蛛池模板: 精品湿| 人禽l交视频在线播放 视频 | 日韩高清一区二区 | 色妞视频一级毛片 | 99福利影院 | 久久精品99国产精品日本 | 99青青青精品视频在线 | 美女张开腿让男人桶的 视频 | 精品国内自产拍在线视频 | 秋霞理论最新三级理论最 | 草逼视频网站 | 糖心vlog视频永久破解版 | 极品美女写真菠萝蜜视频 | 久久囯产精品777蜜桃传媒 | 人妖女天堂视频在线96 | 欧美在线观看网址 | 蹭蹭妈妈的朋友小说 | 双性小说肉| 99撸 | 国产专区视频在线观看 | juliaann大战黑人 | 亚洲大爷操 | 精品视频久久久久 | 九九99热久久999精品 | 美女被到爽流动漫 | luanlun绝对真实乱 | poronovideos变态极限 | 色婷婷综合和线在线 | 魔法满屋免费观看完整版中文 | 明星乱亚洲 | 手机看片福利 | 午夜大片在线观看 | 日韩美一区二区三区 | 亚洲 欧美 中文 日韩欧美 | 3x3x3x短视频在线看 | 亚洲美洲国产日产 | 日韩每日更新 | 成年人在线免费观看视频网站 | 50度灰破解版v5.7.0 | 办公室强行丝袜秘书啪啪 | 亚洲天堂网在线观看视频 |