如何在Go界面中处理重复的方法? [英] How to deal with duplicate methods in Go interface?

查看:210
本文介绍了如何在Go界面中处理重复的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何处理Go界面中的重复方法?

How to deal with duplicate methods in 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")
}

如果我运行此代码,则会发生以下错误.

The following error occurs if I run this code.

$ go run foo.go
# command-line-arguments
./foo.go:24: duplicate method Hello

如何处理这种情况以及如何避免重复 在这种情况下的方法?

How to deal with situations like this and how can we avoid duplicate methods in such a scenario?

推荐答案

做到这一点的方法是显式提供所需的方法,而不是使用速记语法:

The way to do this is to explicitly provide the required methods instead of using the shorthand syntax:

type Entertainer interface {
    Hello()
    Joke()
    Jump()
}

这看起来像是代码重复,但是请注意,重复代码在Go中并不是不常见的事情,尤其是当它导致更清晰的代码时.

This may seem like code duplication, but note that duplicate code isn't an untypical thing in Go, especially when it leads to clearer code.

还要注意这一点:如果您从其他语言的典型继承角度考虑,似乎这样做会丢失一些信息,因为您没有记录到Entertainer inherits ,例如Person.但是Go接口纯粹是结构性的,没有继承.因为Entertainer具有Hello()方法,所以无论您是否在Entertainer声明中明确提及Person,每个Entertainer都将自动为Person.

Also note this: If you think in terms of typical inheritance in other languages, it may seem like you're losing some information by doing this, because you're not recording the fact that Entertainer inherits from, say, Person. But Go interfaces are purely structural, there is no inheritance. Because an Entertainer has a Hello() method, every Entertainer is automatically a Person, whether or not you explicitly mention Person insided the Entertainer declaration.

即使您未对任何接口使用简写语法,所有这些编译也都不会出现问题(已声明且未使用"错误除外)

All of this compiles without problems (except for a "declared and not used" error) even when you don't use the shorthand syntax for any of the interfaces:

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

这是一个完整的程序,可以编译并正常运行.鉴于以下声明:

Here's a complete program that compiles and runs just fine. Given these declarations:

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可以打招呼,跳跃和开玩笑,因此它实现了我们所有的界面.鉴于这四个功能:

A Clown can greet, jump, and joke, and so it implements all of our interfaces. Given these four functions:

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传递给其中任何一个:

you can pass a Clown to any of them:

func main() {
    c := Clown{}

    PersonSayHello(c)
    JokerJoke(c)
    JumperJump(c)
    EntertainerEntertain(c)
}

此处是带有上述代码的前往游乐场的链接.

最后一件事情–您可能会这样说:但是,如果我以后对Person进行更改,则不会在其他界面中反映出来."是的,您必须手动进行这样的调整,但是编译器会告知您.

One final thing – you could argue something like this: "But if I later make a change to Person, it won't be reflected in the other interfaces." It's true, you have to make such an adjustment manually, but the compiler will let you know about it.

如果您具有此功能:

func JumperSayHello(j Jumper) {
    PersonSayHello(j)
}

您的代码可以正常使用.但是,如果向Person添加另一个方法,则依赖于JumperPerson的事实的代码将不再编译.与

your code will work without any issues. But if you add another method to Person, code that relies on the fact that a Jumper is a Person will no longer compile. With

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)

只要您有代码 anywhere (依赖于Jumper始终是Person的事实),情况就会如此.如果您不这样做,甚至没有参加测试,那么–好吧,跳线不认为实际上并不重要吗?

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?

但是,如果出于任何原因实际上需要确保Jumper始终是Person,则无论您对这些接口进行了什么更改,但实际上并没有在任何地方使用此事实,因此您始终可以创建代码为此目的:

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界面中处理重复的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆