在 Go 中,如何隔离返回超过原始值的包?

问题描述 投票:0回答:1

如果我有一个

requests
包,它定义了一个接口
TextExtractor
和一个返回
GetText
类型的
Text
方法,实现必须完全满足
TextExtractor
契约 ,并且他们被迫导入
Text
类型。

我有两种可能的

TextExtractor
实现 - 一种使用 AWS Comprehend,另一种使用 AWS Textract。

文件aws_comprehend.go

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
}

文件request.go

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)
}

文件main.go

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 很固执己见。那么解决这个问题的标准方法是什么?

go interface architecture covariance
1个回答
-1
投票

首先,您的文件布局无效。你不能在同一个文件夹中有两个不同包的文件。所以下面是一个更正的布局。我还删除了所有指针,因为此示例不需要它们,它们只会分散注意力。

最后,我更新了方法以返回正确的类型,以便代码真正编译:

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)
}
© www.soinside.com 2019 - 2024. All rights reserved.