最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang中匿名組合實現(xiàn)偽繼承的方法

 更新時間:2018年08月27日 10:38:53   作者:ggq89  
這篇文章主要介紹了Golang中匿名組合實現(xiàn)偽繼承的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

"Go語言的面向?qū)ο髾C(jī)制與一般語言不同。 它沒有類層次結(jié)構(gòu), 甚至可以說沒有類; 僅僅通過組合( 而不是繼承) 簡單的對象來構(gòu)建復(fù)雜的對象。" -- 《Go語言圣經(jīng)》

1.匿名組合

1.1 匿名組合定義

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

  type Logger struct{
  }
  type Work struct{
    log Logger
  }
  type Work2 struct{
    log *Logger
  }

  func (Logger)Info(v ...interface{}){
  }

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

type Logger struct {
}
type Work struct {
  Logger
}
type Work2 struct {
  *Logger
}

func (Logger) Info(v ...interface{}) {
}

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

1.2 組合對象初始化

非匿名組合初始化方式

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
}

匿名組合初始化

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.匿名組合多個類時,不同的類存在相同的方法,會不會沖突?答案是,不同的類中,不同的方法時不會沖突的,但是在調(diào)用這個方法時,需要明確是那個類中的方法,如果匿名組合進(jìn)來的類得方法,與這個類主體中的方法發(fā)生沖突,那么默認(rèn)情況下,會使用主體類中的方法。

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

示例代碼:

package main
import(
  "bufio"
)
type Reader struct {
}
type Work4 struct {
  Reader
  bufio.Reader
}

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

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

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

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. 結(jié)構(gòu)體嵌入和匿名成員

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

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

type Circle struct {
 Point
 Radius int
} 

type Wheel struct {
 Circle
 Spokes int
}

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

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

同樣的規(guī)則,內(nèi)嵌類型的方法也會提升為外部類型的方法。

3.1 匿名沖突(duplicate field)

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

type Logger struct {
  Level int
}

type MyJob struct {
  *Logger
  Name string
  *log.Logger // duplicate field Logger
}

4. 匿名組合不是繼承

4.1 方法的接受者沒變

當(dāng)我們嵌入一個類型,這個類型的方法就變成了外部類型的方法,但是當(dāng)它被調(diào)用時,方法的接受者是內(nèi)部類型(嵌入類型),而非外部類型?!?Effective Go

type Job struct {
 Command string
 *log.Logger
}

func (job *Job)Start() {
 job.Log("starting now...")
 ... // 做一些事情
 job.Log("started.")
}

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

4.1 內(nèi)嵌類型不是基類

如果讀者對基于 類 來實現(xiàn)的面向?qū)ο笳Z言比較熟悉的話, 可能會傾向于將 內(nèi)嵌類型 看作一個基類, 而 外部類型 看作其子類或者繼承類, 或者將 外部類型 看作 "is a" 內(nèi)嵌類型 。 但這樣理解是錯誤的。

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方法的調(diào)用。 Distance有一個參數(shù)是Point類型, 但q并不是一個Point類, 所以盡管q有著Point這個內(nèi)嵌類型, 我們也必須要顯式地選擇它。 嘗試直接傳q的話你會看到錯誤:

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方法。

實際上,從實現(xiàn)的角度來考慮問題, 內(nèi)嵌字段會指導(dǎo)編譯器去生成額外的包裝方法來委托已經(jīng)聲明好的方法, 和下面的形式是等價的:

func (p ColoredPoint) Distance(q Point) float64 {
 return p.Point.Distance(q)
}

當(dāng)Point.Distance被以上編譯器生成的包裝方法調(diào)用時, 它的接收器值是p.Point, 而不是p。

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

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

type Logger struct {
Level int
}

type MyJob struct {
*Logger
Name string
*log.Logger // duplicate field Logger
}

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

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Go使用XORM操作MySQL的陷阱盤點分析

    Go使用XORM操作MySQL的陷阱盤點分析

    在?Go?語言開發(fā)中,大家為了方便,通常會選擇使用?ORM?操作數(shù)據(jù)庫,比如使用?XORM?或?GORM?操作?MySQL,本文我們來介紹一下使用?XORM[3]?操作?MySQL?可能會遇到的陷阱
    2023-11-11
  • Golang常用的幾種密碼加密方式分享

    Golang常用的幾種密碼加密方式分享

    這篇文章給大家介紹了Golang常用的幾種密碼加密方式,加密有兩種方式,一種是直接加密,一種是鹽值加密,直接加密指的是將原始密碼直接進(jìn)行加密,鹽值加密則是在進(jìn)行密碼加密之前,文中有詳細(xì)的代碼示例,需要的朋友可以參考下
    2023-08-08
  • golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案

    golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案

    這篇文章主要介紹了golang中使用proto3協(xié)議導(dǎo)致的空值字段不顯示的問題處理方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • golang分層測試之http接口測試入門教程

    golang分層測試之http接口測試入門教程

    這篇文章主要介紹了golang分層測試之http接口測試入門教程,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Go 在 MongoDB 中常用查詢與修改的操作

    Go 在 MongoDB 中常用查詢與修改的操作

    這篇文章主要介紹了Go 在 MongoDB 中常用查詢與修改的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go源碼分析之預(yù)分配slice內(nèi)存

    Go源碼分析之預(yù)分配slice內(nèi)存

    這篇文章主要從Go語言源碼帶大家分析一下預(yù)分配slice內(nèi)存的相關(guān)知識,文中的示例代碼簡潔易懂,對我們深入了解go有一定的幫助,需要的可以學(xué)習(xí)一下
    2023-08-08
  • go語言使用pipe讀取子進(jìn)程標(biāo)準(zhǔn)輸出的方法

    go語言使用pipe讀取子進(jìn)程標(biāo)準(zhǔn)輸出的方法

    這篇文章主要介紹了go語言使用pipe讀取子進(jìn)程標(biāo)準(zhǔn)輸出的方法,實例分析了Go語言針對進(jìn)程操作的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • Go語言驅(qū)動低代碼應(yīng)用引擎工具Yao開發(fā)管理系統(tǒng)

    Go語言驅(qū)動低代碼應(yīng)用引擎工具Yao開發(fā)管理系統(tǒng)

    這篇文章主要為大家介紹了Go語言驅(qū)動低代碼應(yīng)用引擎工具Yao開發(fā)管理系統(tǒng)使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • GO項目部署Linux服務(wù)器的實現(xiàn)示例

    GO項目部署Linux服務(wù)器的實現(xiàn)示例

    本文主要介紹了GO項目部署Linux服務(wù)器的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • Go語言中的range用法實例分析

    Go語言中的range用法實例分析

    這篇文章主要介紹了Go語言中的range用法,實例分析了range的功能與使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02

最新評論

息烽县| 拉萨市| 永清县| 平和县| 大英县| 夏津县| 运城市| 黑河市| 房产| 紫金县| 平原县| 南陵县| 昌乐县| 奉化市| 渭源县| 芦山县| 南江县| 神木县| 盘山县| 五原县| 高碑店市| 乌拉特前旗| 漳平市| 布拖县| 肇庆市| 永新县| 碌曲县| 黄平县| 吐鲁番市| 九龙城区| 绿春县| 庆元县| 增城市| 登封市| 新民市| 卫辉市| 吉首市| 南岸区| 北京市| 富平县| 广东省|