类型组合:覆盖接口类型

Type Composition: overriding interface types

我想将一种类型组合成另一种类型,但将其中一个字段(这是一个接口值)替换为假的。我遇到的问题是正在使用基础字段,所以我似乎无法覆盖该字段。

我在这里演示了这个问题:https://play.golang.org/p/lHGnyjzIS-Y

package main

import (
    "fmt"
)

type Printer interface {
    Print()
}

type PrinterService struct {}

func (ps PrinterService) Print() { fmt.Println("PrinterService") }

type Service struct {
    Client PrinterService
}

func (s Service) PrintViaMethod() { s.Client.Print() }

type FakeService struct {
    Service
    Client Printer
}

type SomeOtherService struct {}

func (sos SomeOtherService) Print() { fmt.Println("SomeOtherService") }

func main() {
    s := FakeService{Client: SomeOtherService{}}
    s.PrintViaMethod()
}

为什么会打印"PrinterService"?我想让它打印 "SomeOtherService".

谢谢。

Why does it print 'PrinterService'? I want it to print 'SomeOtherService'.

因为这就是您的代码要求执行的操作。 PrintViaMethod 调用 s.Client.Print()s.ClientPrinterService 的(零值)实例,它输出 PrinterService.

您可能想要在 main() 中调用 s.Print()。我完全看不出你的 PrintByMethod 函数有任何理由。

通过 s.PrintViaMethod(),您正在调用 promoted 方法 FakeService.Service.PrintViaMethod(),方法接收者将是 FakeService.Service,类型为 Service,并且 Service.PrintViaMethod() 调用 Service.Client.Print(),其中 Service.ClientPrinterService 的类型,这就是它打印 "PrinterService".

的原因

Go 中有 embedding, but there is no polymorphism。当您在结构中嵌入类型时,嵌入类型的方法得到提升,并将成为嵌入类型方法集的一部分。但是当这样一个提升的方法被调用时,它会得到嵌入值作为接收者,而不是嵌入者。

要实现您想要的效果,您必须通过为 FakeService 类型(使用 FakeService 接收器类型)提供 PrintViaMethod() 方法的实现来实现 "override" PrintViaMethod() 方法), 并在其中调用 FakeService.Client.Print().

这样做 s.PrintViaMethod() 将表示 FakeService.PrintViaMethod() 方法,因为它将位于 PrintViaMethod() 存在的最浅深度(而不是 FakeService.Service.PrintViaMethod())。这在 Spec: Selectors.

中有详细说明

例如:

func (fs FakeService) PrintViaMethod() {
    fs.Client.Print()
}

然后输出将是(在Go Playground上试试):

SomeOtherService

更多详细信息请参阅相关问题和答案:

根据 Flimzy,您正在调用 print s.Client.Print(),它的类型 PrinterService 实现为 Print() 函数打印 PrinterService 的接收方。您还可以将 Service 结构中 Client PrinterService 的类型更改为 Someother service

package embedded

import (
    "fmt"
)

type Printer interface {
    Print()
}

type PrinterService struct{}

func (ps PrinterService) Print() { fmt.Println("PrinterService") }

type Service struct {
    Client SomeOtherService
}

func (s Service) PrintViaMethod() { s.Client.Print() }

type FakeService struct {
    Service
    Client Printer
}

type SomeOtherService struct{}

func (sos SomeOtherService) Print() { fmt.Println("SomeOtherService") }

func Call() {
    s := FakeService{Client: SomeOtherService{}}
    s.PrintViaMethod()
}