gpt4 book ai didi

go - Go接口(interface)中如何处理重复的方法?

转载 作者:IT王子 更新时间:2023-10-29 00:50:00 24 4
gpt4 key购买 nike

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 添加另一个方法,则依赖于 JumperPerson 这一事实的代码将不再编译。与

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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com