我想撰寫一個可以將某些欄位添加到 Firebase 訊息結構的函式。有兩種不同型別的訊息Message和MulticastMessage,它們都包含相同型別的Android和APNS欄位,但是訊息型別之間沒有明確宣告的關系。
我想我應該能夠做到這一點:
type firebaseMessage interface {
*messaging.Message | *messaging.MulticastMessage
}
func highPriority[T firebaseMessage](message T) T {
message.Android = &messaging.AndroidConfig{...}
....
return message
}
但它給出了錯誤message.Android undefined (type T has no field or method Android)。我也不能寫switch m := message.(type)(cannot use type switch on type parameter value message (variable of type T constrained by firebaseMessage))。
我可以寫switch m := any(message).(type),但我仍然不確定這是否會達到我想要的效果。
我發現人們對聯合和型別約束感到困惑的其他一些 SO 問題,但我看不到任何有助于解釋為什么這不起作用的答案(也許是因為我試圖將它與結構而不是介面一起使用?) 或者聯合型別約束實際上對什么有用。
uj5u.com熱心網友回復:
在 Go 1.18 中,您不能訪問型別引數的公共欄位1或公共方法2。這些功能之所以不起作用,僅僅是因為它們還沒有在該語言中可用。如鏈接執行緒所示,常見的解決方案是為介面約束指定方法。
但是,這些型別*messaging.Message并*messaging.MulticastMessage沒有公共訪問器方法,而是在您無法控制的庫包中宣告。
解決方案一:型別開關
如果聯合中有少量型別,這很好用。
func highPriority[T firebaseMessage](message T) T {
switch m := any(message).(type) {
case *messaging.Message:
setConfig(m.Android)
case *messaging.MulticastMessage:
setConfig(m.Android)
}
return message
}
func setConfig(cfg *messaging.AndroidConfig) {
// just assuming the config is always non-nil
*cfg = &messaging.AndroidConfig{}
}
游樂場:https ://go.dev/play/p/9iG0eSep6Qo
解決方案2:使用方法包裝
這歸結為如何在 Go 中向現有型別添加新方法?然后將該方法添加到約束中。如果您有許多結構,它仍然不太理想,但代碼生成可能會有所幫助:
type wrappedMessage interface {
*MessageWrapper | *MultiCastMessageWrapper
SetConfig(c foo.Config)
}
type MessageWrapper struct {
messaging.Message
}
func (w *MessageWrapper) SetConfig(cfg messaging.Android) {
*w.Android = cfg
}
// same for MulticastMessageWrapper
func highPriority[T wrappedMessage](message T) T {
// now you can call this common method
message.SetConfig(messaging.Android{"some-value"})
return message
}
游樂場:https ://go.dev/play/p/JUHp9Fu27Yt
解決方案3:反射
如果您有許多結構,則最好使用反射。在這種情況下,型別引數不是嚴格需要的,但有助于提供額外的型別安全。請注意,結構和欄位必須是可尋址的才能作業。
func highPriority[T firebaseMessage](message T) T {
cfg := &messaging.Android{}
reflect.ValueOf(message).Elem().FieldByName("Android").Set(reflect.ValueOf(cfg))
return message
}
游樂場:https ://go.dev/play/p/3DbIADhiWdO
筆記:
- 如何將介面中的結構欄位定義為型別約束(型別 T 沒有欄位或方法)?
- 在 Go 泛型中,如何對聯合約束中的型別使用通用方法?
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/493490.html
下一篇:Golang嵌套地圖過濾器
