亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

實現具有更廣泛方法簽名的接口

實現具有更廣泛方法簽名的接口

Go
桃花長相依 2022-09-05 15:28:20
在Go中,有沒有辦法使用方法實現接口,其中實現中相應方法的返回類型是“比”預期的返回類型“寬”的?這很難解釋,所以這里有一個例子。在Go Playground中運行以下示例代碼時,我收到此錯誤:./prog.go:36:14: cannot use BirdImpl{} (type BirdImpl) as type Animal in argument to foo:    BirdImpl does not implement Animal (wrong type for Move method)        have Move() BirdMoveResult        want Move() AnimalMoveResult(其中 是 “wide than” 因為 任何 實現也是BirdMoveResultAnimalMoveResultBirdMoveResultAnimalMoveResult)package maintype (    Animal interface {        Move() AnimalMoveResult    }    Bird interface {        Move() BirdMoveResult    }    AnimalMoveResult interface {        GetDistance() int    }    BirdMoveResult interface {        GetDistance() int        GetHeight() int    }    BirdImpl struct{}    BirdMoveResultImpl struct{})// Some implementation of BirdImpl.Move// Some implementation of BirdMoveResultImpl.GetDistance// Some implementation of BirdMoveResultImpl.GetHeightfunc foo(animal Animal) int {    return animal.Move().GetDistance()}func main() {    foo(BirdImpl{})  // This fails because BirdImpl doesn't implement Animal. My question is why not?}我知道由于返回類型不同,方法簽名不完全匹配,因此Go不考慮作為的實現。但是,如果 Go 比較返回類型,則 的任何實現也會實現 。那么,不應該是一個可接受的實現(如果不是,為什么不呢)?Move()BirdImplAnimalBirdMoveResultAnimalMoveResultMove() BirdMoveResultMove() AnimalMoveResult編輯:在實際方案中,、 和 是外部包的一部分。在我自己的代碼中,我希望能夠使用我自己的接口方法進行擴展(如示例中所做的那樣),同時仍然能夠使用擴展接口來使用。AnimalAnimalMoveResultfooAnimalMoveResultBirdMoveResultfoo
查看完整描述

3 回答

?
蝴蝶不菲

TA貢獻1810條經驗 獲得超4個贊

這些類型的問題通常是以下結果:


過早的接口

假界面,或“氣泡包裝”(請參閱我的咆哮 這里)

并行接口

您遇到的錯誤與第 3 個問題最具體相關,但每個錯誤都存在于此處的示例設計中。


好的接口應該傳達(以它們的名稱和方法簽名)一組行為。接口的名稱應由它包含的方法暗示,因為該名稱只是應該捕獲該行為的本質。


為此目的似乎唯一需要的接口是:


type Mover interface {

    Move() MoveResult

}

對于 MoveResult,您可以執行此操作(如果您愿意,可以使用 int 交換 float):


type MoveResult struct {

    Distance, Height float64

}

給定以下假設,此類型可以作為結構很好地發揮作用:


移動結果只是數據點(它們不需要是動態的;您可以設置值并保留它們)

“額外”數據(如高度)在未指定時以零值正確運行。

現在,實現 bird 類型:


type Bird struct {

    // some internal data

}


func (b *Bird) Move() MoveResult {

    // some movement calculations

    return MoveResult{Distance: howFar, Height: howHigh}

}

現在實現 foo:


func foo(m Mover) float64 {

    return m.Move().Distance

}

現在主要使用它:


func main() {

    foo(&Bird{})

}

現在我們可以將其他類型的s添加到程序中,并毫無問題地使用它們。Moverfoo


解決您的注釋,其中 和 都是外部的,您無法修改它們:AnimalAnimalMoveResultfoo


我如何用我的理解提出問題:有這個函數,旨在接受一個名為的接口,其特征是它如何返回專有類型。您希望將類型用作 ,但無法將所需的所有行為都適合該專有返回類型。fooAnimalBirdAnimal


那么如何解決這個問題呢?


實現您自己的、更廣泛的返回類型


type birdMoveResult struct {

    // some internal data

}


func (r birdMoveResult) GetDistance() int {

    // get the distance

}


func (r birdMoveResult) GetHeight() int {

    // get the height

}

現在,實現 Bird 類型


type Bird struct {

    // some internal data

}


func (b *Bird) Move() AnimalMoveResult {

    var result birdMoveResult

    // calculate the move result

    return birdMoveResult

}

請注意,返回類型,因此現在將滿足接口。我們能夠做到這一點,因為滿足類型,所以在這里返回它是合法的。MoveAnimalMoveResultBirdAnimalbirdMoveResultAnimalMoveresult


剩下的問題是 s 方法縮小了寬界面的范圍,我們實際上已經丟失了您添加的新功能。為了在仍然滿足接口的同時將其取回,我們根本無法更改方法簽名。以下是 2 種可能的解決方法。BirdMoveAnimalMove


使用 bird 類型時,您可以對結果進行類型斷言,以訪問額外的方法

var b Bird

// ...

height := b.Move().(birdMoveResult).GetHeight()

向中添加一個新方法,該方法返回更廣泛的類型,使現有方法具有相同的簽名BirdMove

func (b *Bird) MoveFull() birdMoveResult {

    var result birdMoveResult

    // calculate the move result

    return birdMoveResult

}


func (b *Bird) Move() AnimalMoveResult {

    return b.MoveFull()

}


height := b.MoveFull().GetHeight()

這些都可以工作,這主要是偏好問題。


查看完整回答
反對 回復 2022-09-05
?
大話西游666

TA貢獻1817條經驗 獲得超14個贊

在Go中,有沒有辦法使用方法實現接口,其中實現中相應方法的返回類型是“比”預期的返回類型“寬”的?

不。方法簽名必須按字面匹配。圍棋沒有協變或逆變的概念。


查看完整回答
反對 回復 2022-09-05
?
繁花如伊

TA貢獻2012條經驗 獲得超12個贊

Go的類型系統使用類型名稱匹配。即使使用不同的類型名稱返回相同的接口,此操作也會失敗。

但是,您可以聲明該方法以滿足接口,但返回可以類型斷言的更廣泛的實現。


查看完整回答
反對 回復 2022-09-05
  • 3 回答
  • 0 關注
  • 98 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號