首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >围棋中的嵌入与继承

围棋中的嵌入与继承
EN

Stack Overflow用户
提问于 2022-01-15 11:16:27
回答 2查看 736关注 0票数 2

我正在努力学习Go,但我不断地抨击它的一些与其他语言不同的概念。

假设我有一个结构

代码语言:javascript
复制
type Vehicle struct {
    Seats int
}

现在我想要另一个结构,它嵌入了Vehicle

代码语言:javascript
复制
type Car struct {
    Vehicle
    Color string
}

据我所知,Car结构现在嵌入了Vehicle

现在我想要一个函数,它可以使用任何车辆

代码语言:javascript
复制
func getSeats(v Vehicle){
    return v.Seats
}

但是每当我试图传递一个Car

代码语言:javascript
复制
    getSeats(myCar)

我得到以下错误:

cannot use myCar (value of type Car) as Vehicle value in argument to getSeats

但是我的IDE告诉我myCar有一个Seats属性!

由此,我了解到嵌入与继承是不一样的。

我的问题是:是否存在类似于结构继承(如c++ )的结构继承,其中一个函数可以接受一个基本结构,或者这是否与Go处理完全不同?我将如何在“前进之路”中实现这样的东西?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-01-15 11:38:31

就像你提到的,Go没有典型意义上的继承。嵌入实际上只是语法上的糖。

嵌入时,可以向结构中添加一个字段,其名称与嵌入类型完全相同。嵌入结构的任何方法都可以在嵌入它们的结构上调用,这只不过是转发它们而已。

一个问题是,如果嵌入另一个方法的结构已经声明了一个方法,那么它将被优先于转发它,如果您想这样想的话,它允许您覆盖一些函数。

正如您已经注意到的,即使Car嵌入了Vehicle,我们也不能将它们作为Vehicle使用,因为它们完全不是相同的类型。但是嵌入Vehicle的任何结构都将包含由Vehicle定义的所有方法,因此如果我们定义了Vehicle实现的接口,那么嵌入Vehicle的所有类型也应该实现该接口。

例如:

代码语言:javascript
复制
package main

import (
    "fmt"
)

type Seater interface {
    Seats() int
}

type Vehicle struct {
    seats int
}

func (v *Vehicle) Seats() int {
    return v.seats
}

type Car struct {
    Vehicle
    Color string
}

type Bike struct {
    Vehicle
    Flag bool
}

// A bike always has 1 seat
func (b *Bike) Seats() int {
    return 1
}

type Motorcycle struct {
    Vehicle
    Sidecar bool
}

// A motorcycle has the base amounts of seats, +1 if it has a side car
func (m *Motorcycle) Seats() int {
    return m.Vehicle.seats + 1
}

func getSeats(v Seater) int {
    return v.Seats()
}

func main() {
    fmt.Println(getSeats(&Bike{
        Vehicle: Vehicle{
            seats: 2, // Set to 2 in the Vehicle
        },
        Flag: true,
    }))

    fmt.Println(getSeats(&Motorcycle{
        Vehicle: Vehicle{
            seats: 1,
        },
        Sidecar: true,
    }))

    fmt.Println(getSeats(&Car{
        Vehicle: Vehicle{
            seats: 4,
        },
        Color: "blue",
    }))
}

这些指纹:

代码语言:javascript
复制
1
2
4

Bike的情况下,调用Bike.Seats方法,这就是为什么它返回1,即使它的Vehicleseats值是2

Motorcycle的情况下,Motorcycle.Seats方法也被调用,但是在这里我们可以访问嵌入式类型并仍然使用它来获得结果。

Car的情况下,调用Vehicle.Seats方法是因为Car没有“覆盖”Seats

票数 3
EN

Stack Overflow用户

发布于 2022-01-15 12:12:13

这是我一开始就关心的事情。我认为使用像Java这样的OOP语言的概念是自然的方式。当然,Go不是面向对象的,也不是通过继承来实现多态性的。最后,支持的组合从继承提供的东西中获取好的东西,并删除那些增加了更多开销的东西,然后是有效的帮助。Go对多态性的回答是接口。Go试着变得简单,而你通常只能用一种显而易见的方式来完成事情。假设您有这样的Java类:

代码语言:javascript
复制
class Base {
    private int attribute;

    public int getAttribute() {
        return this.attribute;
    }
}

class Something extends Base {}

在java中,每个对象都在堆上,并且您有指向它的指针。它可以是null,这也意味着当您传递它时,它的大小是相同的。这是您可以更自由地传递对象的原因之一(无论您传递Base还是Something,只要参数类型是超类,它就会编译)。Go的设计是为了更有效地管理内存,比堆更多地使用堆栈,甚至堆也不那么支离破碎。当您声明一个struct时,该结构的大小取决于它所保存的数据,因此您不能将它传递到嵌入式结构所属的位置。让我们举一个例子:

代码语言:javascript
复制
type Base struct {
   attribute int32 
}

func (b *Base) Attribute() int32 {
    return b.attribute
}

type Something struct {
    garbage int32
    Base
}

Base有4个字节,Something有8个字节,attribute有不同的偏移量。如果编译器允许您以Something代替Base,那么您将访问garbage而不是attribute。如果您想要得到这种行为,您必须使用接口。幸运的是,您需要声明的是:

代码语言:javascript
复制
type BaseInterface interface {
    Attribute() int32
}

既然您有了这个接口,就可以对嵌入Base的所有结构(除非它还嵌入了具有相同级别的方法名Attribute的其他东西)进行通用函数,如下所示:

代码语言:javascript
复制
func DoubleOfBaseAttribute(base BaseInterface) int32 {
    return base.Attribute() * 2
}

这也被称为动态调度( Dynamic ),以及C++或Java等语言隐式使用的内容。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70720911

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档