Golang中接口方法返回另一个接口的实现问题
Golang中接口方法返回另一个接口的实现问题 关于在Go中正确实现接口的问题,特别是涉及使用链式方法的第三方包时。我整理了一个示例项目,以便您能理解这个问题。
package main
import (
myAPI "github.com/hashicorp/vault/api"
)
var myClient *myAPI.Client
type MyProvider interface {
GetClient() MyAPIClient
}
type MyAPIClient interface {
// 我想这样做,但它不工作
Logical() MyAPILogical
// 不过这样是可行的
// Logical() *myAPI.Logical
}
type MyAPILogical interface {
Write(path string, data map[string]interface{}) (*myAPI.Secret, error)
}
type Provider struct {}
func PublicFunctionIWantToTest(provider MyProvider) {
client := provider.GetClient()
// 我们通常在这里对 `client` 变量做一些操作,但重要的是我们稍后会传递它
privateFunctionThatIsUsedInTheTest(client)
}
func privateFunctionThatIsUsedInTheTest(client MyAPIClient) (*myAPI.Secret, error) {
return client.Logical().Write(
"/here/goes/some/path",
map[string]interface{}{
"key": "value",
},
)
}
func NewProvider() MyProvider {
return Provider{}
}
func (p Provider) GetClient() MyAPIClient {
return myClient
}
// 空函数,仅为了使此示例能够构建
func main() {}
如您所见,该包有一个链式方法 Logical().Write()。由于我想为 PublicFunctionIWantToTest 创建测试,我希望将所有功能通过接口传递,以便可以使用 mockery 为其创建模拟。
不幸的是,我在 MyAPIClient 和 MyAPILogical 接口上遇到了问题。从包的文档(api package - github.com/hashicorp/vault/api - Go Packages)中可以看到,Logical() 方法返回一个 Logical 实例,我希望让接口方法返回另一个接口 MyAPILogical(第15行)。但这并不奏效,GetClient() 方法(第47行)出现错误,提示我没有正确实现接口。我该如何解决?
cannot use myClient (variable of type *api.Client) as MyAPIClient value in return statement: *api.Client does not implement MyAPIClient (wrong type for method Logical)
have Logical() *api.Logical
want Logical()
非常感谢。
更多关于Golang中接口方法返回另一个接口的实现问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢你的帮助 @skillian!
更多关于Golang中接口方法返回另一个接口的实现问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我不熟悉那个包,也还没完全理解你试图实现的大局,但你之所以遇到那个错误,正如你所说,是因为 (*api.Client).Logical 返回的是 *api.Logical,而不是 MyAPILogical。即使 *api.Logical 实现了该接口,MyAPIClient 接口也必须被精确匹配。
一个变通方法是将 *api.Client 类型包装到一个结构体中,并通过它来实现你的 Logical 函数:
type myAPIClient struct{ *myAPI.Client }
func (c myAPIClient) Logical() MyAPILogical {
return c.Client.Logical()
}
var myClient myAPIClient
在Go中,接口实现是隐式的,但必须满足方法签名完全匹配。您遇到的问题是因为*api.Client的Logical()方法返回的是*api.Logical,而您的接口要求返回MyAPILogical。虽然*api.Logical实现了MyAPILogical接口(因为它有Write方法),但返回类型不匹配。
解决方案是使用适配器模式包装原始类型。以下是修正后的代码:
package main
import (
myAPI "github.com/hashicorp/vault/api"
)
var myClient *myAPI.Client
type MyProvider interface {
GetClient() MyAPIClient
}
type MyAPIClient interface {
Logical() MyAPILogical
}
type MyAPILogical interface {
Write(path string, data map[string]interface{}) (*myAPI.Secret, error)
}
// 适配器包装*api.Client
type clientAdapter struct {
client *myAPI.Client
}
func (c *clientAdapter) Logical() MyAPILogical {
return &logicalAdapter{logical: c.client.Logical()}
}
// 适配器包装*api.Logical
type logicalAdapter struct {
logical *myAPI.Logical
}
func (l *logicalAdapter) Write(path string, data map[string]interface{}) (*myAPI.Secret, error) {
return l.logical.Write(path, data)
}
type Provider struct{}
func PublicFunctionIWantToTest(provider MyProvider) {
client := provider.GetClient()
privateFunctionThatIsUsedInTheTest(client)
}
func privateFunctionThatIsUsedInTheTest(client MyAPIClient) (*myAPI.Secret, error) {
return client.Logical().Write(
"/here/goes/some/path",
map[string]interface{}{
"key": "value",
},
)
}
func NewProvider() MyProvider {
return Provider{}
}
func (p Provider) GetClient() MyAPIClient {
return &clientAdapter{client: myClient}
}
func main() {}
这个方案创建了两个适配器:
clientAdapter包装*api.Client,实现MyAPIClient接口logicalAdapter包装*api.Logical,实现MyAPILogical接口
这样您就可以使用mockery为MyAPIClient和MyAPILogical生成模拟对象进行测试。

