Go接口(interface)中如何处理重复的方法?
package main
import (
"fmt"
)
type Person interface {
Hello()
}
type Joker interface {
Person
Joke()
}
type Jumper interface {
Person
Jump()
}
type Entertainer interface {
Joker
Jumper
}
func main() {
fmt.Println("hello, world")
}
如果我运行这段代码,会出现以下错误。
$ go run foo.go
# command-line-arguments
./foo.go:24: duplicate method Hello
如何处理这样的情况,我们如何避免重复 这种情况下的方法?
最佳答案
这样做的方法是显式提供所需的方法,而不是使用简写语法:
type Entertainer interface {
Hello()
Joke()
Jump()
}
这看起来像是代码重复,但请注意,重复代码在 Go 中并非不常见,尤其是当它导致更清晰的代码时。
另请注意:如果您从其他语言的典型继承的角度考虑,这样做似乎会丢失一些信息,因为您没有记录 Entertainer
的事实继承,比如说,人
。但是 Go 接口(interface)是纯结构的,没有继承。因为 Entertainer
有一个 Hello()
方法,所以每个 Entertainer
都会自动成为一个 Person
,无论您是否显式在 Entertainer
声明中提及 Person
。
即使您不对任何接口(interface)使用速记语法,所有这些都可以毫无问题地编译(除了“已声明且未使用”错误):
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
可以打招呼、跳跃和开玩笑,因此它实现了我们所有的接口(interface)。鉴于这四个功能:
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
进行更改,它不会反射(reflect)在其他界面中。”确实,您必须手动进行这样的调整,但编译器会让您知道。
如果你有这个功能:
func JumperSayHello(j Jumper) {
PersonSayHello(j)
}
您的代码可以正常运行。但是,如果您向 Person
添加另一个方法,则依赖于 Jumper
是 Person
这一事实的代码将不再编译。与
type Person interface {
Hello()
Think()
}
你得到
.\main.go:18: cannot use j (type Jumper) as type Person in argument to PersonSayHello: Jumper does not implement Person (missing Think method)
This will be the case as long as you have code anywhere that relies on the fact that a Jumper
is always a Person
. And if you don't, not even in your tests, then – well, maybe it doesn't actually matter that the jumper doesn't think?
But if for whatever reason you actually need to ensure that a Jumper
is always a Person
, no matter what changes you make to these interfaces, but this fact isn't actually used anywhere, you can always create code just for this purpose:
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() {
}
关于go - Go接口(interface)中如何处理重复的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43730255/