如果我有一个
requests
包,它定义了一个接口 TextExtractor
和一个返回 GetText
类型的 Text
方法,实现必须完全满足 TextExtractor
契约 ,并且他们被迫导入Text
类型。
我有两种可能的
TextExtractor
实现 - 一种使用 AWS Comprehend,另一种使用 AWS Textract。
package aws_comprehend
type AwsComprehend struct{}
func (a *AwsComprehend) GetText() *Text {
// do some stuff with aws comprehend...
return &Text{
Text: "text",
Language: "language",
}
}
type Text struct {
Text string
Language string
}
package requests
import "fmt"
type TextExtractor interface {
GetText() *Text
}
type Text struct {
Text string
Language string
}
func HandleRequest(textExtractor TextExtractor) {
text := textExtractor.GetText()
fmt.Println(text)
}
package main
import (
"aws_comprehend"
"requests"
)
func main() {
textExtractor := new(aws_comprehend.AwsComprehend)
requests.HandleRequest(textExtractor)
// this does not work:
// cannot use textExtractor (variable of type *aws_comprehend.AwsComprehend) as
// requests.TextExtractor value in argument to requests.HandleRequest:
// *aws_comprehend.AwsComprehend does not implement requests.TextExtractor
// (wrong type for method GetText)
// have GetText() *aws_comprehend.Text
// want GetText() *requests.Text
}
我明白为什么这行不通。这是因为 Go 不支持Covariant Result Types。但我的问题是,对这种情况进行编码的标准方法是什么? Go 提供隐式接口的事实意味着隔离包非常容易:调用包定义它使用的接口,并传递实现这些接口的实现。这意味着包根本不需要相互引用。但是,如果一个包定义了一个接口,它返回的不仅仅是一个原始值,那么你就必须有意识地共享这些值类型。如果
GetText
返回 string
,上面的代码就没问题。但它返回 struct
或其他接口的事实意味着代码不能这样写。
我想让
requests
包对aws_comprehend
包一无所知。这是因为我有两种 TextExtractor
接口的实现:一种使用 AWS Comprehend,另一种使用 AWS Textract。我 also 不希望包含一个“中间”包,它具有 requests
包和 aws_comprehend
包继承的接口。如果两个包都必须继承相同的接口,那么这对我来说似乎只是间接耦合,它破坏了隐式接口的想法。
我知道 Go 很固执己见。那么解决这个问题的标准方法是什么?
首先,您的文件布局无效。你不能在同一个文件夹中有两个不同包的文件。所以下面是一个更正的布局。我还删除了所有指针,因为此示例不需要它们,它们只会分散注意力。
最后,我更新了方法以返回正确的类型,以便代码真正编译:
aws_comprehend/aws_comprehend.go
:
package aws_comprehend
import "hello/requests"
type AwsComprehend struct{}
func (AwsComprehend) GetText() requests.Text {
return requests.Text{}
}
requests/request.go
:
package requests
import "fmt"
type TextExtractor interface {
GetText() Text
}
type Text struct {
Language string
Text string
}
func HandleRequest(textExtractor TextExtractor) {
text := textExtractor.GetText()
fmt.Println(text)
}
main.go
:
package main
import (
"hello/aws_comprehend"
"hello/requests"
)
func main() {
var textExtractor aws_comprehend.AwsComprehend
requests.HandleRequest(textExtractor)
}