学习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实现,这很重要,因为。
- 你不需要事先知道是哪一个。
- 你可以很容易地模拟这种依赖关系,以达到测试目的。
- 你可以根据你的不同需要选择使用哪一个
然而,有一种情况值得一提,当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的完整工作例子。