继承和接口

huangapple go评论85阅读模式
英文:

Inheritance and interfaces

问题

我想表达的是许多编程语言中的extends行为。

在我的Go代码中,我有几个结构体,如下所示:

type Base struct {
    // 一些字段
}

type BaseExtender struct {
    Base
    // 独特的字段
}

type AnotherBaseExtender struct {
    Base
    // 独特的字段
}

现在,我想编写一个函数,它接受任何Base类型,因为我只需要它的“相似字段”。

func UseTheBase(b Base) {
    testVal := b.thingICareAbout
}

然而,这样做不起作用。我已经研究了一些关于interface的内容,并且认为我可以这样做:

type Base interface {
    // 一些字段
}

但是,Go似乎通过方法实现自动推断接口。有没有办法模拟这种行为,以便我可以将任何Base类型传递给我的函数,而不必在Base结构体及其所有扩展结构体上实现一些空操作方法?

谢谢!

英文:

I want to express the extends behavior many languages possess.

In my Go Code I have a few structs that look like so:

type Base struct {
        // Some fields
}

type BaseExtender struct {
        Base
        // Unique fields
}

type AnotherBaseExtender struct {
        Base
        // Unique fields
}

Now, I want to write a function that takes any Base since I only need it's "similar fields".

func UseTheBase(b Base) {
        testVal := b.thingICareAbout
}

However, this doesn't work. I've done some digging into interface and thought I could do something like:

type Base interface {
        // Some fields
}

Except it appears that Go automatically infers interfaces by method implementation. Is there a way to mimic this behavior so I can pass any Base into my function, and not have to implement some nop method on the Base struct and all of it's extenders?

Thanks!

答案1

得分: 3

Base意味着你想在Go中使用继承,但Go故意避免了继承,不要试图重新创建它。你可以嵌入类型,但要将其视为嵌入行为,而不仅仅是数据(就像你可能在继承语言中尝试的那样)。

你的解决方案是正确的,但需要公共方法,是的,接口是根据方法来定义的。只需在调用它的地方定义接口:

type Doer interface {
    DoSomething()
}

...

func doit(d Doer) {
    d.DoSomething()
}

doit函数不关心它的参数是什么,只要它有一个DoSomething方法即可。显然,这是一个简单的示例,没有什么意义,但如果你需要在所有扩展者中覆盖某些内容,请问自己为什么需要Base存在,如果它只是为了添加一些字段,那可能没有足够的理由使用单独的类型,只需在需要它们的地方添加字段即可。

尽量避免在其他语言中可能构建的大量类型分类。

英文:

Base implies you want inheritance in Go, Go deliberately eschews inheritance, don't try to recreate it. You can embed types but think of this as embedding behaviour, not just data (as you might be tempted to in an inheriting language).

You're on the right lines with your solution but need public methods and yes interfaces are defined in terms of methods. Just define the interface where you call it as:

type Doer interface {
DoSomething()
}

...
func doit(d Doer) {
   d.DoSomething()
}

doit doesn't care what its argument is as long as it has a DoSomething method. Obviously this is a trivial example and there's no point in it, but if you need to override something in all extenders, ask yourself why Base exists, if it is just to add some fields, that's probably not enough reason for a separate type, just add the fields where you need them.

Try to avoid the vast taxonomies of types that you might construct in other languages.

答案2

得分: 0

另外,我经常使用的一种常见模式是:

type Base interface {
    SomeFunction() int
}

type SimpleBaseImpl struct {
    // 独特的字段
}

func (s SimpleBaseImpl) SomeFunction() int {
    return 0
}

type SomethingMoreComplicated struct {
    SimpleBaseImpl
    // 独特的字段
}

然后你可以将 SomethingMoreComplicated 视为 "type" Base - 但是再次强调,Go 语言更倾向于组合(如此处所示)而不是继承。

英文:

To add on, a common pattern I use is:

type Base interface {
	SomeFunction() int
}

type SimpleBaseImpl struct {
	// Unique fields
}

func (s SimpleBaseImpl) SomeFunction() int {
	return 0
}

type SomethingMoreComplicated struct {
	SimpleBaseImpl
	// Unique fields
}

Then you could treat SomethingMoreComplicated as "type" Base – but again, its important to note the golang preference for composition (shown here) over inheritance.

huangapple
  • 本文由 发表于 2017年3月15日 14:09:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/42802229.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定