在Go 1.18中,您不能访问类型参数的公共字段,也不能访问类型参数的公共方法.这些功能无法正常工作,因为它们在该语言中尚不可用.如链接线程所示,常见的解决方案是为接口约束指定方法.
但是,类型*messaging.Message
和*messaging.MulticastMessage
没有通用的访问器方法,并且在您无法控制的库包中声明.
Solution 1: type switch
如果联合体中有少量类型,那么这种方法可以很好地工作.
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
Solution 2: wrapper with method
这可以归结为How to add new methods to an existing type in Go?,然后将该方法添加到约束中.如果有许多 struct ,这仍然不够理想,但代码生成可能会有所帮助:
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
Solution 3: reflection
如果您有许多 struct ,那么最好使用反射.在这种情况下,并不严格需要类型参数,但有助于提供额外的类型安全性.请注意, struct 和字段必须为addressable才能工作.
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
笔记:
- How can I define a struct field in my interface as a type constraint (type T has no field or method)?
- In Go generics, how to use a common method for types in a union constraint?