泛型:实现嵌套接口

分享于2023年02月15日 generics go 问答
【问题标题】:Generics: Implement nested interfaces泛型:实现嵌套接口
【发布时间】:2023-02-09 05:59:01
【问题描述】:

我正在尝试使用泛型实现接口 Interface 。它有一个方法接受另一个接口作为参数:

type SubInterface interface {
    SendResponse(string)
}

type Interface interface {
    Subscribe(SubInterface)
}

我想出了这些接口的以下通用版本:

type GenericSubInterface[T any] interface {
    SendResponse(T)
}

type GenericInterface[Res any] interface {
    Subscribe(GenericSubInterface[Res])
}

我希望 GenericInterface[string] 可以分配给 Interface 但不知何故不是。

var a Interface
var b GenericInterface[string]

//  cannot use b (variable of type GenericInterface[string]) as Interface value in assignment: GenericInterface[string] does not implement Interface (wrong type for method Subscribe)
//      have Subscribe(GenericSubInterface[string])
//      want Subscribe(SubInterface)
a = b

创建 Interface 的通用实现也不起作用:

type GenericImplementation[Res any] struct {
}

func (i *GenericImplementation[Res])Subscribe(ss GenericSubInterface[Res]) {
    var msg Res
    ss.SendResponse(msg)
}
//  cannot use &GenericImplementation[string]{} (value of type *GenericImplementation[string]) as Interface value in variable declaration: *GenericImplementation[string] does not implement Interface (wrong type for method Subscribe)
//      have Subscribe(GenericSubInterface[string])
//      want Subscribe(SubInterface)
var c Interface = &GenericImplementation[string]{}

我觉得奇怪的是子接口可以相互分配:

var d SubInterface
var e GenericSubInterface[string]

// works fine
d = e

这个问题似乎只在接口以某种方式嵌套时才会出现。有没有办法解决这个问题,我可以使用泛型来实现 string 以外的类型的 Interface

Full playground example


【解决方案1】:

首先,阅读 Go interface: interface not implemented even though it is @colm.anseo 的回答的第一句话已经总结了这个问题:

签名不一样。参数类型不同

然后阅读 How to implement generic interfaces? SubInterface 类型的值可分配给 一个特定的实例 GenericSubInterface ,即 GenericSubInterface[string] ,因为方法最终是相同的—— SendResponse(string)

Interface 不能分配给 GenericInterface[string] 因为这些方法最终被 不相同 .错误消息就像它得到的一样雄辩:

have Subscribe(GenericSubInterface[string])
want Subscribe(SubInterface)

您可以使用接口的通用版本,但是必须准确地实现这些方法。所以你也必须使函数 AcceptInterface 通用:

func AcceptInterface[T any](a GenericInterface[T]) {
}

func main() {
    var b GenericInterface[string]
    AcceptInterface(b)
}

【讨论】: