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,请替换any
为interface{}
. 此选项与选项 1 有点相同,只是Item
接口为空。
优点
避免类型参数;适用于 Go 1.18 之前的版本。
对可以发布的内容没有限制。
已发布的项目不会隐藏在界面后面。
订阅者可以接收多种项目。
发布者可以发布多种项目。
缺点
需要反射或投射,这是缓慢、笨拙且不太安全的。
订户将不得不做额外的工作来弄清楚他们收到了什么样的项目。
- 1 回答
- 0 关注
- 124 浏览
添加回答
举报