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

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

Golang:創建一個接口來抽象可能具有可變參數的方法

Golang:創建一個接口來抽象可能具有可變參數的方法

Go
慕絲7291255 2023-03-07 11:36:36
我寫了一些創造“人類”的代碼。人類每 100 毫秒過一次生日,您可以像這樣訂閱事件:    pers1 := new(Human)    pers1.Init("John")    pers1.Subscribe(func(h Human) { fmt.Printf("Observer1 : %s", h.String()); return })    pers1.Subscribe(func(h Human) { fmt.Printf("Observer2 : %s", h.String()); return })    time.Sleep(3 * time.Second)輸出如下HUMAN John is born  // by initHUMAN John is now followed by 0x4901a0   // by subscribeThere is now 1 observersHUMAN John is now followed by 0x490300   // by subscribeThere is now 2 observers[T+0100ms]HUMAN John has its birthday      // after 100ms : birthday happensObserver1 : HUMAN : John is 1   // callbackObserver2 : HUMAN : John is 1   // callback// ... continue for 3 seconds詳細代碼在這里,但問題不在 https://goplay.tools/snippet/7qsZ1itcqrS我的問題如下:我想創建一個接口Producer對應于產生我可以訂閱的事件的事物。您可以訂閱:過生日的人可檢測濕度變化的濕度傳感器收到郵件的郵件服務器...在我的例子中,回調函數有一個參數:一個Human。那個年齡變了...以相同的方式,濕度傳感器的給定事件將期望傳感器結構。我的問題是我認為這樣做有意義嗎?(這是一個學者問題,沒有工作)如果是,如何。我找不到相關的例子那將是type Producer interface{      Subscribe( func( < something variable >) )}我無法得到一些工作。我也很難為這個問題找到一個好的標題。隨意給我一個更好的。
查看完整描述

1 回答

?
波斯汪

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

根據您的需要,此處提供三個可能適合您的選項。


選項 1:已發布項目的通用界面

不僅為可以擁有訂閱者的發布者創建一個接口,而且為那些發布者可以發布的東西創建一個接口:


type Item interface{

  Description() string

  Age() int

}


type human struct{

  age int

}


func (h *human) Description() string {

  return "human"

}


func (h *human) Age() int {

  return h.age

}


type Publisher interface{

  Subscribe(func(Item))

}


type humanProducer struct{

  subscribers []func(Item)

}


func (hp *humanProducer) Subscribe(f func(Item) {

  hp.subscribers = append(hp.subscribers, f)

}


// Example use

func addSubscriber(p Publisher, f func(Item)) {

  p.Subscribe(f)

}


func main() {

  hp := &humanProducer{}

  addSubscriber(p, func(i Item) {

    fmt.Printf("Got a %s that is %d years old.\n", i.Description(), i.Age())

  })

}

您現在可以通過讓它們實現接口來設置要發布的其他類型的東西Item。這里的和方法只是示例——您可以在其中添加任何您需要的方法Description。Age

優點

  • 避免反射。

  • 避免類型參數;適用于 Go 1.18 之前的版本。

  • 訂閱者可以接收多種項目。

  • 發布者可以發布多種項目。

缺點

  • 已發布的項目不能只是任何東西——您必須定義一組預先確定的功能,所有類型的已發布項目都必須具有這些功能。

  • 已發布的項目隱藏在界面后面,因此您只能使用界面中公開的功能Item,除非您開始強制轉換或使用反射。


選項 2:使用類型參數的接口

將類型參數添加到接口本身:

type human struct{

  age int

}


type Publisher[T any] interface{

  Subscribe(func(T))

}


type humanProducer struct{

  subscribers []func(*human)

}


func (hp *humanProducer) Subscribe(f func(*human) {

  hp.subscribers = append(hp.subscribers, f)

}


// Example use

func addSubscriber[T any](p Publisher[T], f func(T)) {

  p.Subscribe(f)

}


func main() {

  hp := &humanProducer{}

  addSubscriber[*human](p, func(h *human) {

    fmt.Printf("Got a human that is %d years old.\n", h.age)

  })

}

優點

  • 避免反射。

  • 對可以發布的內容沒有限制。

  • 已發布的項目不會隱藏在界面后面。

缺點

  • 發布者只能發布一種特定類型的項目。

  • 訂戶只能收到一種特定的物品。

  • 接口的任何使用都Publisher需要使用類型參數。僅適用于 Go 1.18 或更高版本。


選項 3:反射/鑄造

允許發布者發布任何內容,并在訂閱者中使用反射或強制轉換來確定發布的內容類型:

type human struct{

  age int

}


type Publisher interface{

  Subscribe(func(any))

}


type humanProducer struct{

  subscribers []func(any)

}


func (hp *humanProducer) Subscribe(f func(any) {

  hp.subscribers = append(hp.subscribers, f)

}


// Example use

func addSubscriber(p Publisher, f func(any)) {

  p.Subscribe(f)

}


func main() {

  hp := &humanProducer{}

  addSubscriber(p, func(i any) {

    if h, ok := any.(*human); ok {

      fmt.Printf("Got a human that is %d years old.\n", h.age)

    }

  })

}

如果使用 1.18 之前的 Go,請替換anyinterface{}. 此選項與選項 1 有點相同,只是Item接口為空。

優點

  • 避免類型參數;適用于 Go 1.18 之前的版本。

  • 對可以發布的內容沒有限制。

  • 已發布的項目不會隱藏在界面后面。

  • 訂閱者可以接收多種項目。

  • 發布者可以發布多種項目。

缺點

  • 需要反射或投射,這是緩慢、笨拙且不太安全的。

  • 訂戶將不得不做額外的工作來弄清楚他們收到了什么樣的項目。


查看完整回答
反對 回復 2023-03-07
  • 1 回答
  • 0 關注
  • 155 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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