为什么 Go 允许结构体实现存在于不同包中的未导出接口?

Why does Go allow a struct to implement an unexported interface present in a different package?

我写了一个示例代码来了解 unexported interface 是如何工作的。在下面的示例中,我在 service 包中声明了 unexported repoInterface

TestRepo struct in the repo package implements unexported repoInterface 没有任何问题。

Code structure
repo
  repo.go
service
  service.go
main.go

service.go

// service/service.go

// this is the interface which the TestRepo struct implements in repo package
type repoInterface interface{
    GetName() string
}

type TestService struct{
    repo repoInterface
}

func NewTestService(r repoInterface) TestService {
    return TestService{
       repo: r,
    }
}

func (s TestService) GetName() string {
    return s.repo.GetName()
}

repo/repo.go

// repo/repo.go
type TestRepo struct{
    name string
}

func NewTestRepo(name string) TestRepo {
    return TestRepo{
        name: name,
    }
}

// implements repoInterface present in service package
func (r TestRepo) GetName() string {
    return r.name
}

main.go

func main() {
    testRepo := repo.NewTestRepo("hello")
    testService := service.NewTestService(testRepo)
    fmt.Println(testService.GetName())
}

// Output
// hello

我目前的假设:

This isn't possible since repo and service are different packages.

TestRepo struct present in repo package cannot implement the Unexported interface present in the service package. This is the reason why we export interfaces.

现在我意识到这不是真的,我的理解是错误的。

问题:

为什么 Go 允许实现存在于不同包中的未导出接口?

service.NewTestService 包函数需要任何实现 type interface{ GetName() string }.

的值

repoexports a type TestRepo 公开了一个方法 GetName() string.

在将 repo.TestRepo 传递给 service.NewTestService 函数后,如 service.NewTestService(testRepo),该值通过提供预期的 method set.

来实现接口

一切顺利。

类型 service.repoInterface declares a not exported identifier 仅区分可以使用该接口名称的包。

我在剧中转载了你的例子https://go.dev/play/p/bp6z2HjwdLS


包含未导出标识符的接口类型声明是 sealed 接口。

那些密封的接口不能被国外的包实现。

它可以是一个不导出的方法名,如

type Fooer interface {
    Foo() 
    sealed()
}

在这里尝试 https://go.dev/play/p/3Syh7R0uS-q

它也可以使用未导出的参数类型声明一个方法,


type Foo interface {
    GetName() string
    GetName2() sealed
}

type sealed int