Go语言将接口类型作为功能,类似于C风格的接口。但是,Go的接口类型似乎没有被强制执行 - 它们只是定义协议而不实际应用于类型。由于它们没有强制执行,使用接口仍然是个好主意吗?
答案 0 :(得分:7)
是。 Go不允许您构建类型层次结构,因此接口对于允许某些多态性非常重要。考虑一下sort
包中定义的sort.Interface
:
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less returns whether the element with index i should sort
// before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
sort
包中包含一个函数sort(data Interface)
,它需要任何实现此接口的对象。如果没有接口,那么这种形式的多态性就无法实现。您不必显式注释您的类型实现此接口的事实是无关紧要的。
关于go的很酷的部分是你甚至可以在基本类型上实现这个接口,只要在同一个包中定义类型。因此,以下代码定义了一个可排序的整数数组:
type Sequence []int
// Methods required by sort.Interface.
func (s Sequence) Len() int {
return len(s)
}
func (s Sequence) Less(i, j int) bool {
return s[i] < s[j]
}
func (s Sequence) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
答案 1 :(得分:1)
是的,使用接口仍然是一个好主意。强调界面。参见https://talks.golang.org/2014/go4gophers.slide#5。扩展@ElianEbbing出色的答案,任何类型的方法和临时接口都可以实现轻量级的OO编程风格。参见https://talks.golang.org/2012/goforc.slide#48。
一个例子可以说明这一点。
package main
import . "fmt"
func main() {
c.Cry() // Meow
Cryer.Eat(c) // Fish
}
var c = cat{"Fish"}
type cat struct{ s string }
type Eater interface{ Eat() }
type Cryer interface {
Cry()
Eater
}
func (c cat) Eat() { Println(c.s) }
func (cat) Cry() { Println("Meow") }
通过Cryer
界面,您可以访问Cry()
和Eat()
方法。参见https://talks.golang.org/2012/zen.slide#16。您可以将Cryer
添加到基础代码中而无需更改。参见https://stackoverflow.com/a/11753508/12817546。如果将其删除,该代码也可以正常工作。您仍然可以直接访问c.Cry()
所示的方法。这是因为Go可以让您做两件事。
首先,您可以隐式实现接口。接口只是一组方法。参见https://talks.golang.org/2013/go4python.slide#33。接口变量可以存储任何非接口值,只要它实现接口的方法即可。参见https://blog.golang.org/laws-of-reflection。 可以将实现接口的所有方法的任何类型的值分配给该接口的变量。参见https://talks.golang.org/2014/taste.slide#20。
c
是cat
的变量。 cat
实现了Eat()
和Cry()
方法。 Eater
显式实现Eat()
。 Cryer
显式实现Cry()
和Eat()
。因此,cat
隐式实现了Eater
和Cryer
接口。参见https://talks.golang.org/2012/goforc.slide#40。因此,c
的变量cat
可以是Eater
和Cryer
的变量。参见https://golang.org/doc/effective_go.html#blank_implements。
第二,结构和接口类型可以嵌入其他结构和接口类型中。参见https://golang.org/doc/effective_go.html#embedding。 Cryer.Eat(c)
会调用Eat()
,因为它嵌入了Eater
。因此,Go中的接口是解耦程序组件的主要手段。参见https://www.reddit.com/r/golang/comments/6rwq2g。以及为什么接口可以在包,客户端或服务器之间提供良好的API。参见https://stackoverflow.com/a/39100038/12817546。
如果看不到好处,请不要添加界面。请参阅https://stackoverflow.com/a/39100038/12817546中的评论。没有明确的层次结构,因此无需设计层次结构!参见https://talks.golang.org/2012/goforc.slide#46。在需要时添加接口。首先定义数据类型,然后逐步构建1-3个方法interface
。参见https://stackoverflow.com/a/11753508/12817546。编辑引号以匹配示例。
答案 2 :(得分:0)
我希望知道什么是类型检查,统计和运行时间,但我不知道什么是“强制执行接口”。