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

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

在 Golang 中,消費者如何為接受接口的函數定義接口?

在 Golang 中,消費者如何為接受接口的函數定義接口?

Go
翻閱古今 2023-02-21 16:49:07
如果我正確理解 Go 實踐,調用者(也稱為消費者)應該從他們的依賴項(也稱為生產者)中定義他們想要使用的接口。但是,如果生產者有一個接受自定義類型的函數,那么最好讓它接受一個接口,對吧?這樣消費者就可以傳遞一些符合生產者接口的值,而不知道確切的類型。因為生產者函數的輸入值使生產者成為該輸入值的“消費者”。好吧,很公平。問題是,消費者如何定義一個接口,其中包含一個函數,其參數是生產者定義的接口?試圖使問題更清楚假設我有一個名為chefstruct 的包Chef。它有一個方法Cut(fruit) error,fruit是在我的包中定義的一個接口chef?,F在假設我在調用代碼中,我導入了 package chef。我想給它一個水果來切,但在我的例子中,我實現了一個名為Apple. 自然地,我會嘗試為自己構建這個界面:type myRequirements interface {   Cut(Apple) error}因為我有接口的具體實現fruit叫Apple,所以我想說明我的接口只適用于蘋果。但是,如果我嘗試針對我的界面使用Chef{},Go 將拋出編譯錯誤,因為我的界面想要Cut(Apple)和Chef{}想要的Cut(Fruit)。盡管 Apple 實現了fruit.避免這種情況的唯一方法似乎是制作chef.Fruit一個公共界面,并在我自己的界面中使用它。type myRequirements interface {   Cut(chef.Fruit) error}但這完全破壞了我在接口下插入不同實現(而不是chef)的能力,因為現在我與chef.所以 Chef 有一個內部接口fruit,但調用者只知道 Apple。我如何在調用者的界面中指示應該輸入什么Cut而不引用chef?回答評論“你為什么需要 myRequirements?”我很驚訝這不是 Go 社區中更一致的概念。我需要 myRequirements 接口的原因是因為我是 chef 包的消費者。此外Cut,廚師可能還有100多種方法。但我只使用Cut. 我想向其他開發人員表明,在我的情況下,我只使用Cut. 我還想讓測試只模擬Cut我的代碼工作。此外,我需要能夠插入不同的實現Cut(來自不同的廚師)。這是我帖子開頭提到的 golang 最佳實踐。
查看完整描述

3 回答

?
胡子哥哥

TA貢獻1825條經驗 獲得超6個贊

我會說這歸結為你能控制什么。在您的示例中,您似乎描述了兩個單獨的包。有多種方法可以處理此問題:


接受一個函數


您可以修改ApiFunction以接受處理您想要的情況的功能:


type consumerDeps interface {

    ApiFunction(func() string) string

}

這將允許您將您想要的確切功能注入消費者。然而,這里的缺點是這會很快變得混亂,并且會混淆定義函數的意圖,并在實現接口時導致意想不到的后果。


接受接口{}


您可以修改ApiFunction以接受interface{}由實現接口的人處理的對象:


type consumerDeps interface {

    ApiFunction(interface{}) string

}


type producer struct{}


type apiFunctionInput interface {

    hello() string

}


func (producer) ApiFunction(i interface{}) string {

    return i.(apiFunctionInput).hello()

}

這稍微好一點,但現在您依賴于生產者端正確解釋數據,如果它沒有執行此操作所需的所有上下文,那么如果它轉換為,您可能會出現意外行為或恐慌錯誤的類型。


接受第三方接口


您還可以創建一個第三方接口,在這里稱之為適配器,它將定義生產者端和消費者端都可以同意的功能:


type Adapter interface {

    hello() string

}


type consumerDeps interface {

    ApiFunction(Adapter) string

}

現在,您有一個數據合同,可用于由消費者發送和由生產者接收。這可能像定義一個單獨的包一樣簡單,也可能像整個存儲庫一樣復雜。


重新設計


最后,你可以重新設計你的代碼庫,這樣生產者和消費者就不會像這樣耦合在一起。雖然我不知道您的具體用例,但您遇到這個特定問題這一事實意味著您的代碼耦合得太緊,可能應該重新設計。消費者端和生產者端包之間可能有一個元素拆分,可以提取到第三個包。


查看完整回答
反對 回復 2023-02-21
?
qq_遁去的一_1

TA貢獻1725條經驗 獲得超8個贊

我不太清楚你為什么要介紹這個myRequirements界面。如果Chef需要一個FruittoCut并且你想定義一個特定的水果Apple- 你需要做的就是定義一個Apple實現接口的結構Fruit。


type Chef struct {

}


type fruit interface {

    Cut() error

}


func (c Chef) Cut(fruit fruit) error {

    return fruit.Cut()

}


然后,您需要做的就是根據您的要求定義Apple實現接口的對象:Fruit


package kitchen


import chef "goplayground/interfaces/fruits/chef"


type Apple struct {

}


func (a Apple) Cut() error {

    // lets cut

    return nil

}


type myRequirements interface {

    Cut(Apple) error

}


type myChef struct {

    chef chef.Chef

}


func (m myChef) Cut(apple Apple) error {

    // since Apple implements the chef`s fruit interface this is possible

    return m.chef.Cut(apple)

}


func cook() {

    remy := myChef{}

    apple := Apple{}

    _ = remy.Cut(apple)

}


查看完整回答
反對 回復 2023-02-21
?
慕娘9325324

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

正確使用 duck-typing 有一些細微差別,這就是 Go 類型系統在接口方面的作用。在使用它們的地方定義接口通常是一個好習慣,但io.Reader接口是在標準庫中定義的。因此,該建議的適用性有限。


在你的例子中,包chef有兩個接口,Chef和Fruit. 這兩個接口緊密耦合,因為Chef有一個方法使用Fruit. 使用當前的 Go 類型系統,Chef如果不從該包中導出就無法使用Fruit。所以:


type myRequirements interface {

  Cut(chef.Fruit) error

}

是您可以使用包中的實現的chef.Chef唯一方法。Apple


但是你想要做的是:


type myRequirements interface {

  Cut(Apple) error

}

并且您希望能夠傳達這是 的子集Chef,也就是說, 的語義Cut與 的語義相同Chef。好吧,語義是不同的。否則是不安全的。


說,你實施Apple為:


type Apple struct {}


func (a Apple) SomeFunc()

func (a Apple) FruitFunc()

而是chef.Fruit:


type Fruit interface {

   FruitFunc()

}

顯然,Appleimplements chef.Fruit,因此您可以傳遞到需要Applea 的任何地方。chef.Fruit但是你不能傳遞chef.Fruit給myRequirements.Cut(Apple)函數。因為 in myRequirements.Cutyou 也暗示你可以使用Apple.SomeFunc, which is not defined in chef.Fruit.


所以,如果你真的想定義一個像 的接口myRequirements,那么你必須使用chef.Fruit. 如果你定義的是using Apple,那么myRequirements.Cut方法就不同于chef.Cut。


查看完整回答
反對 回復 2023-02-21
  • 3 回答
  • 0 關注
  • 173 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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