学习Go的嵌入指南

69 阅读2分钟

学习Go的嵌入指南

Go中的一个很酷的功能是嵌入;我们可以把它比作类继承(如果你想把它比作什么,而且你来自基于类的编程语言),但它并不一样。

Effective Go包含了对这一特性的一个很好的简要介绍,我将其扩展一下。

假设我们有一个假想的创业公司 "Greetings Y'all",它正计划颠覆问候的世界!他们的MVP包括一个。他们的MVP包括一个GreetingsService ,其中包括两个问候语。"你好 "和 "早上好"。

type GreetingsService interface {
	SayHello() string
	SayGoodMorning() string
}

因为所有的种子资金都快用完了,Greetings Y'all正在实施第一个只有英文的版本。

type EnglishService struct {
	Country string
}

func (EnglishService) SayHello() string {
	return "hello!"
}

func (EnglishService) SayGoodMorning() string {
	return "good morning!"
}

几天过去了,GreetingsService ,成为一个巨大的成功!因此,问候Y'all实施了其他语言的不同版本,如。西班牙语和普通话。

随着时间的推移,Greetings Y'all决定作为他们统治世界的下一步,引入(不管出于什么原因)另一个不相关的服务,恰好可以问候他们的用户,称为GiveMeYourMoneyService

type GiveMeYourMoneyService struct {
	GreetingsService
	Country string
}

func (GiveMeYourMoneyService) SayGoodMorning() string {
	return "$$$"
}

(是的,他们决定总是说$$$ ,而不是早安,我想是创业者的生活)。

这个新结构的有趣之处在于它是如何嵌入一个接口的,这样你就可以指定你想要的任何具体的GreetingsService实现,这很重要,因为。

  1. 你不需要事先知道是哪一个。
  2. 你可以很容易地模拟这种依赖关系,以达到测试目的。
  3. 你可以根据你的不同需要选择使用哪一个

然而,有一种情况值得一提,当GiveMeYourMoneyService 决定嵌入EnglishService ,通过嵌入这个特定的具体实现,它将隐藏(或阴影)名为Country的字段,因为两种类型都使用同一个字段。

那么,我们如何才能访问这个特定的字段呢?你必须将该类型转换为具体实现。

o := GiveMeYourMoneyService{GreetingsService: &EnglishService{Country: "Neverland"}, Country: "Sokovia"}
fmt.Printf("FancierService: %+v\n", o)
fmt.Printf("FancierService.SayHello: %s\n", o.SayHello())
fmt.Printf("FancierService.GoodMorning: %s\n", o.SayGoodMorning())

var e1 *EnglishService = o.GreetingsService.(*EnglishService)
fmt.Printf("original.Country: %s\n", e1.Country)

请看这个gist的完整工作例子。