如何支持同一接口的多个版本?

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

How can I support multiple versions of same interface?

问题

我正在编写一个实现满足接口的结构的 Go 模块。我们只想维护一个库的单个版本,但我们的客户使用我们一个依赖的多个版本。

该依赖项提供了我们想要实现的接口,如下所示:

type SuperCoolInterface interface {
    DoOldCoolThing(value string)
}

我们的实现如下所示:

type SuperCoolImpl struct {}

func (sc *SuperCoolImpl) DoOldCoolThing(value string) {}

依赖项的新版本在 types 模块中添加了一个新类型。

type NewType struct {
  value string
}

该依赖项在接口中添加了一个方法。

type SuperCoolInterface interface {
    DoOldCoolThing(value string)
    DoNewCoolThing(value types.NewType)
}

现在,如果我实现了新方法,它将无法与旧版本的库编译,因为 types.NewType 不存在。然而,如果我不实现新版本,我将无法满足新版本的接口。

type SuperCoolImpl struct {}

func (sc *SuperCoolImpl) DoOldCoolThing(value string) {}
func (sc *SuperCoolImpl) DoNewCoolThing(value types.NewType) {}

我们需要分叉我们的代码以支持这个版本吗?在具有预处理器的语言中,有一个简单的解决方案,所以我认为 Go 必须有一个我不知道的解决方案。

我们计划继续开发并支持两个版本,所以需要确保两个不同版本的一致性可能会很麻烦。我希望能够使用反射或类似于 C 的预处理器的方法来解决这个问题,在其中我可以定义一个预处理器值,并且只在我们指示库的版本具有正确类型时实现该方法。

英文:

I am writing a go module that implements a struct that satisfies an interface. We only want to maintain a single version of our library, but our clients use multiple versions of one of our dependencies.

The dependency provides an interface we want to implement, like this.

type SuperCoolInterface interface {
    DoOldCoolThing(value string)
}

And our implementation is like this.

type SuperCoolImpl struct {}

func (sc *SuperCoolImpl) DoOldCoolThing(value string) {}

The new version of the dependency adds a new type in a types module.

type NewType struct {
  value string
}

The dependency adds a method to the interface.

type SuperCoolInterface interface {
    DoOldCoolThing(value string)
    DoNewCoolThing(value types.NewType)
}

Now if I implement the new method, it won't compile with the old version of the library, since types.NewType does not exist. However, if I don't implement the new version, I won't satisfy the new version of the interface.

type SuperCoolImpl struct {}

func (sc *SuperCoolImpl) DoOldCoolThing(value string) {}
func (sc *SuperCoolImpl) DoNewCoolThing(value types.NewType) {}

Do we need to fork our code in order to support this version? In languages with preprocessors there is an easy solution for this, so I am assuming Go must have a solution I am missing.

We are planning to continue development and support both versions, so it would be annoying to need to ensure two different version maintain consistency. I was hoping I could do something with reflection or something similar to C's preprocessor where I can define a preprocessor value and only implement the method when we indicate the version of the library has the correct type.

答案1

得分: 2

我找到了适合我情况的解决方案。

感谢 @Burak Serdar 指导我朝正确的方向。

我的解决方案是将旧的实现放入 impl/v0 包中,将新的实现放入 impl/v1 包中。

使用旧版本依赖的客户端将使用 impl/v0,而使用新版本依赖的客户端将使用 impl/v1。

由于 golang 只编译直接导入的代码,只有具有正确版本接口的包将被编译,因此可以在两个方向上成功编译。

这解决了我对不得不分叉整个库的担忧。

编辑:如果有人使用这个解决方案,在当前使用 go test ./... 运行测试时有一个注意事项。该命令似乎会尝试构建每个模块,而不管其中是否有测试。

但是你可以使用 go test $(go list ./... | grep -v <PATH_TO_IGNORE>) 排除测试,然后可以使用另一个命令对正确版本运行这些测试。

英文:

I figured out a solution that works for my situation.

Thanks @Burak Serdar for aiming me in the right direction.

My solution is to put the old implementation into impl/v0 package, and the new implementation into impl/v1 package.

The clients who use the old version of the dependency will use impl/v0, and the clients that use the new version of the dependency will use impl/v1.

Since golang only compiles the code that was imported directly, only the package with the correct version of the interface will be compiled, so will successfully compile in both directions.

The alleviates my concern about having to fork the entire library.

Edit: If anyone uses this solution there is one gotcha if you are currently running your tests with go test ./.... That command seems to try and build every module, regardless of if it has tests in it or not.

But you can exclude tests with go test $(go list ./... | grep -v &lt;PATH_TO_IGNORE&gt;), and then you can run those tests against the correct version in another command.

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

发表评论

匿名网友

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

确定