点击上方蓝色“Golang来啦”关注我哟
加个“星标”,天天 15 分钟,掌握 Go 语言
你好,我是小四,你情商高,也可以叫我四哥~
Go 语言不同于我们所知道的其他语言,比如 Java、C#等。常常使用鸭子类型处理依赖关系。通过声明一个本地接口,指定想要依赖的方法,但是不提供具体的实现,就像下面这样:
// Notice that the interface does not even need to be exported
// for an outside dependency to satisfy it.
type doer interface {
Do()
}
func doStuff(d doer) {
d.Do()
}
任何实现了 Do() 方法的类型都是 doer 接口依赖实现。
按照惯例,Go 标准库中的大多数接口都很小(声明的方法少)。Go 社区流行的一句谚语:
“接口越大,抽象能力越弱”
然而,在实际开发的时候,接口通常会包含很多个方法,所以违背了上面这条谚语。因此,看到一个接口声明了 10-15 个方法并不奇怪。比如,当开发者想要抽象出数据库的详细操作时,就会面临这种情况。
假设你遇到这种情况,并且需要提供一个函数的模拟实现,这个函数里面可能最多只会使用其中的一两个方法。你会实现其他方法来满足这个接口吗?
其中一个方法就是实现全部的方法,但是这种方式在测试的时候是不灵活的。
在我的实践中,我发现一简单的方法,只需要实现其中一个方法就能实现接口,就是通过接口嵌入的方式。
请看下面的例子:
type Store interface {
FindLatestOrder() (Order, error)
FindCustomerByID(id int) (Customer, error)
FindProductByID(id int) (Product, error)
// ... and many more
}
func doSomething(s Store) {
latestOrder, _ := s.FindLatestOrder() // error checks ignored for brevity
u, _ := s.FindCustomerByID(latestOrder.CustomerID)
fmt.Println(u.ID)
}
Store 接口包含很多方法,但是函数里面只用到了其中两个。那我们怎么才能在不实现接口所有方法的情况下,满足函数的要求呢?
type dummyStore struct{}
func main() {
doSomething(&dummyStore{})
}
上面的代码会导致编译出错。
然而,下面的代码不仅可以编译还能执行:
type dummyStore struct{
Store
}
func (ds *dummyStore) FindLatestOrder() (Order, error) {
return Order{CustomerID: 42, ProductID: 24}, nil
}
func (ds *dummyStore) FindCustomerByID(id int) (Customer, error) {
return Customer{ID: 42}, nil
}
// NOTE that we are not implementing FindProductByID
func main() {
doSomething(&dummyStore{})
}
那这是怎么做到的?其实是因为接口嵌入的原因,Store 接口嵌入结构体 dummyStore,结构体会自动获得接口的所有方法,并且结构体还可以实现自己的方法。
因为我们在实例化 dummyStore 时没有提供 Store 的具体实现,所以它的值为 nil,因此如果调用任何一个属于 Store 的,但是 dummyStore 没有实现的方法,将会导致错误 nil pointer dereference。
简而言之,这就是如何在 Go 语言实现一个大型接口。这也是一个关于接口嵌入结构体的很好示例。但是,请谨慎使用。
via: https://preslav.me/2023/02/22/partially-implemented-interfaces-in-golang/
作者:Preslav Rachev
资料获取
今天扫码加我微信,回复「资料」,就可以免费、限时领取上面的全部资料。另外,还会拉你进专属 Go 语言交流群,大家一起抱团学习成长!!!
(你扫我?还是我扫你?)
这是持续翻译的第 9/100 篇优质文章。
如果你有想交流的话题,欢迎留言。
如果您的朋友也在学习 Go 语言,相信这篇文章对 TA 有帮助,欢迎转发分享给 TA,非常感谢!