【问题标题】:Type Composition: overriding interface types类型组合:覆盖接口类型
【发布时间】:2018-06-13 06:27:40
【问题描述】:

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

我在这里演示了这个问题: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"

谢谢。

【问题讨论】:

    标签: go struct interface embedding overriding


    【解决方案1】:

    为什么要打印“PrinterService”?我希望它打印“SomeOtherService”。

    因为这就是您的代码所说的。 PrintViaMethod 调用s.Client.Print()s.ClientPrinterService 的(零值)实例,输出PrinterService

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

    【讨论】:

    • 我添加PrintViaMethod 的原因是我试图复制我在模拟AWS 服务客户端时遇到的问题,就像它说的in the documentation 一样。我的代码似乎很难放在这里,所以我试图提炼问题。可能是我做的不对。
    • 我遇到的问题是当我调用something.Client.InterfaceMethod() 时,它使用了正确的客户端,但是当我调用something.Method() 时,它又通过客户端调用,客户端似乎为零。我的理论是我没有正确地覆盖客户端。
    • go 中根本没有覆盖。你为什么要尝试以这种方式模拟某些东西?
    • 这听起来像是一个 XY 问题。你专注于你的解决方案,而不是问题。要解决什么问题?
    【解决方案2】:

    s.PrintViaMethod(),你正在调用 promoted 方法FakeService.Service.PrintViaMethod(),方法接收者将是FakeService.Service,其类型为ServiceService.PrintViaMethod() 调用Service.Client.Print() ,其中Service.ClientPrinterService 的类型,这就是它打印"PrinterService" 的原因。

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

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

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

    例如:

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

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

    SomeOtherService
    

    查看相关问题和答案,了解更多详情:

    Go embedded struct call child method instead parent method

    Does fragile base class issue exist in Go?

    【讨论】:

      【解决方案3】:

      根据Flimzy,您正在调用 print s.Client.Print(),它的类型为 PrinterService,实现为 Print() 函数打印 PrinterService 的接收器。您还可以将Service结构中ClientPrinterService的类型更改为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()
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-08
        • 2019-06-05
        • 2018-07-13
        • 1970-01-01
        • 2012-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多