泛型:实现嵌套接口

huangapple go评论79阅读模式
英文:

Generics: Implement nested interfaces

问题

我正在尝试使用泛型实现接口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]

// 无法将b(类型为GenericInterface[string]的变量)赋值给Interface:GenericInterface[string]未实现Interface(Subscribe方法的类型不正确)
// 具有Subscribe(GenericSubInterface[string])方法
// 期望Subscribe(SubInterface)
a = b

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

type GenericImplementation[Res any] struct {
}

func (i *GenericImplementation[Res]) Subscribe(ss GenericSubInterface[Res]) {
	var msg Res
	ss.SendResponse(msg)
}
// 无法将&GenericImplementation[string]{}(类型为*GenericImplementation[string]的值)作为Interface值在变量声明中使用:*GenericImplementation[string]未实现Interface(Subscribe方法的类型不正确)
// 具有Subscribe(GenericSubInterface[string])方法
// 期望Subscribe(SubInterface)
var c Interface = &GenericImplementation[string]{}

让我感到奇怪的是,子接口可以相互赋值:

var d SubInterface
var e GenericSubInterface[string]

// 正常工作
d = e

问题似乎只发生在接口嵌套的情况下。有没有办法绕过这个问题,以便我可以使用泛型实现除了string之外的其他类型的Interface

完整的 playground 示例

英文:

I'm trying to implement the interface Interface using generics. It has one method which accepts another Interface as a parameter:

type SubInterface interface {
	SendResponse(string)
}

type Interface interface {
	Subscribe(SubInterface)
}

I've come up with the following generic version of those interfaces:

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

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

I would expect GenericInterface[string] to be assignable to Interface but it somehow isn't.

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

Creating a generic implementation of Interface doesn't work either:

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]{}

What seems weird to me is that the sub-interfaces are assignable to each other:

var d SubInterface
var e GenericSubInterface[string]

// works fine
d = e

The problem only seems to occur when interfaces are nested somehow. Is there any way around this that I can implement Interface using generics for types other than string?

Full playground example

答案1

得分: 3

首先,阅读 https://stackoverflow.com/questions/63586621/go-interface-interface-not-implemented-even-though-it-is@colm.anseo 的回答的第一句话已经总结了问题:

> 签名不同。参数类型不同。

然后阅读 https://stackoverflow.com/questions/72034479/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)
}
英文:

First, read https://stackoverflow.com/questions/63586621/go-interface-interface-not-implemented-even-though-it-is. The very first sentence of @colm.anseo's answer already summarizes the issue:

> The signatures are not the same. The argument types are different

Then read https://stackoverflow.com/questions/72034479/how-to-implement-generic-interfaces. Values of type SubInterface are assignable to a particular instantiation of GenericSubInterface, namely GenericSubInterface[string], because the methods end up being identical — SendResponse(string).

Interface is not assignable to GenericInterface[string] because the methods end up being not identical. The error message is as eloquent as it gets:

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

You can use the generic version of your interfaces, however the methods must be implemented exactly. So you have to make the function AcceptInterface generic too:

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

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

答案2

得分: 1

我已经找到了一个适合我的用例的使用泛型来满足Interface的解决方案。任何嵌套的接口都必须作为额外的类型参数进行指定。这使得实例化过程更加冗长,但允许GenericInterfaceGenericImplementation满足Interface

// Interface

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

var a Interface
var b GenericInterface[string, SubInterface]
a = b // 可行

// Implementation

type GenericImplementation[Res any, Arg GenericSubInterface[Res]] struct {
}

func (i *GenericImplementation[Res, Arg]) Subscribe(ss Arg) {
    var msg Res
    ss.SendResponse(msg)
}

var c Interface = &GenericImplementation[string, SubInterface]{} // 可行
英文:

I've found a solution to satisfy Interface using generics that fits my use case. Any nested interface has to be specified as an additional type parameter. This makes the instantiation a little more verbose but allows for GenericInterface and GenericImplementation to satisfy Interface:

// Interface

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

var a Interface
var b GenericInterface[string, SubInterface]
a = b // works

// Implementation

type GenericImplementation[Res any, Arg GenericSubInterface[Res]] struct {
}

func (i *GenericImplementation[Res, Arg]) Subscribe(ss Arg) {
    var msg Res
    ss.SendResponse(msg)
}

var c Interface = &GenericImplementation[string, SubInterface]{} // works

huangapple
  • 本文由 发表于 2023年2月9日 02:23:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75390159.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定