这样做的方法是显式提供所需的方法,而不是使用简写语法:
type Entertainer interface {
Hello()
Joke()
Jump()
}
这看起来像是代码重复,但请注意,重复代码在 Go 中并不是不常见的事情,尤其是当它导致代码更清晰时。
还要注意这一点:如果您考虑其他语言的典型继承,这样做似乎会丢失一些信息,因为您没有记录Entertainer 继承 来自,比如说,Person。但是 Go 接口是纯结构的,没有继承。因为Entertainer 具有Hello() 方法,所以每个Entertainer 都自动成为Person,无论您是否在Entertainer 声明中明确提及Person。
即使您不使用任何接口的简写语法,所有这些都可以毫无问题地编译(“已声明且未使用”错误除外):
var e Entertainer
var ju Jumper
var jo Joker
var p Person
p = e // every Entertainer is also a Person
p = ju // every Jumper is also a Person
p = jo // every Joker is also a Person
ju = e // every Entertainer is also a Jumper
jo = e // every Entertainer is also a Joker
这是一个完整的程序,可以正常编译和运行。鉴于这些声明:
package main
import (
"fmt"
)
type Person interface {
Hello()
}
type Joker interface {
Hello()
Joke()
}
type Jumper interface {
Hello()
Jump()
}
type Entertainer interface {
Hello()
Joke()
Jump()
}
让我们创建一个Clown 类型:
type Clown struct {}
func (c Clown) Hello() {
fmt.Println("Hello everybody")
}
func (c Clown) Joke() {
fmt.Println("I'm funny")
}
func (c Clown) Jump() {
fmt.Println("And up I go")
}
Clown 可以打招呼、跳跃和开玩笑,因此它实现了我们所有的接口。鉴于这四个功能:
func PersonSayHello(p Person) {
p.Hello()
}
func JumperJump(j Jumper) {
j.Jump()
}
func JokerJoke(j Joker) {
j.Joke()
}
func EntertainerEntertain(e Entertainer) {
e.Joke()
e.Jump()
}
您可以将Clown 传递给他们中的任何一个:
func main() {
c := Clown{}
PersonSayHello(c)
JokerJoke(c)
JumperJump(c)
EntertainerEntertain(c)
}
Here's a link to a Go Playground with the above code.
最后一件事——你可以这样争论:“但如果我稍后对Person 进行更改,它不会反映在其他界面中。”确实,你必须手动进行这样的调整,但是编译器会让你知道的。
如果你有这个功能:
func JumperSayHello(j Jumper) {
PersonSayHello(j)
}
您的代码将毫无问题地运行。但是,如果您向Person 添加另一个方法,则依赖于Jumper 是Person 这一事实的代码将不再编译。与
type Person interface {
Hello()
Think()
}
你得到
.\main.go:18: 不能在 PersonSayHello 的参数中使用 j(类型 Jumper)作为 Person 类型:
Jumper 没有实现 Person(缺少 Think 方法)
只要您的代码任何地方 都依赖于Jumper 始终是Person 这一事实,就会出现这种情况。如果你不这样做,甚至在你的测试中,那么——好吧,也许跳线不思考实际上并不重要?
但是,如果出于某种原因您确实需要确保 Jumper 始终是 Person,无论您对这些接口进行什么更改,但实际上并没有在任何地方使用这一事实,您始终可以创建代码仅出于此目的:
package main
type Person interface {
Hello()
}
type Jumper interface {
Hello()
Jump()
}
// this function is never used, it just exists to ensure
// interface compatibility at compile time
func ensureJumperIsPerson(j Jumper) {
var p Person = j
_ = p
}
func main() {
}