继承 – 在Go中创建复杂的结构层次结构的惯用方法是什么?

我在Go写一个解释器,我正在寻找存储AST的惯用方法.我读了Go编译器源代码,似乎他们使用带有空方法的接口来表示AST.例如,我们有以下层次结构,

Object
--Immovable
----Building
----Mountain
--Movable
----Car
----Bike

这就是上述层次结构以“空方法”的方式实现的方式.

type Object interface {
  object()
}

type Immovable interface {
  Object
  immovable()
}

type Building struct {
  ... 
}

type Mountain struct {
  ... 
}

type Movable interface {
  Object
  movable()
}

type Car struct {
  ...
} 

type Mountain struct {
  ...
} 

func (*Building) object() {}
func (*Mountain) object() {}
func (*Car) object() {}
func (*Bike) object() {}
func (*Building) immovable() {}
func (*Mountain) immovable() {}
func (*Car) movable() {}
func (*Bike) movable() {}

上面的代码是一个人为的例子,这就是Go编译器implemented如何使用几十个空方法的AST.但为什么?请注意定义了多少个空方法.随着层次深度的增加,它可能变得非常复杂.

评论中指出,空方法不允许分配不兼容的类型.在我们的示例中,例如,* Car不能分配给* Immovable.

在支持继承的C等其他语言中,这很容易.我想不出任何其他代表AST的方式.

Go编译器AST的实现方式可能是惯用的,但是不是不那么简单吗?

Go是 not (quite) an object oriented language:它没有类,它是 does not have type inheritance;但它支持一个类似的结构,在结构级和接口级都称为嵌入,它确实有 methods.

Go中的Interfaces只是固定的方法集.如果接口的方法集是接口的超集(没有intent的声明),则类型隐式地实现接口.

如果要明确记录或声明类型确实实现了接口(因为没有明确说明),那么空方法很棒.官方Go FAQ: How can I guarantee my type satisfies an interface?

type Fooer interface {
    Foo()
    ImplementsFooer()
}

如果要在类型层次结构中进行区分(例如,您不希望允许对象同时具有Movable和Immovable),则它们必须具有不同的方法集(Movable的每个方法集中必须至少有1个方法)并且不存在于另一个的不可移动的),因为如果方法集将包含相同的方法,一个的实现也会自动实现另一个,因此您可以将Movable对象分配给Immovable类型的变量.

将空方法添加到具有相同名称的接口将为您提供此区别,假设您不会将此类方法添加到其他类型.

减少空方法的数量

就个人而言,我对空方法没有任何问题.有一种方法可以减少它们.

如果您还为层次结构中的每个类型创建了一个struct实现,并且每个实现都将结构实现嵌入了一个更高级别,那么更高一级的方法集将自动生成,而不会更进一步:

宾语

对象接口和ObjectImpl实现:

type Object interface {
  object()
}
type ObjectImpl struct {}
func (o *ObjectImpl) object() {}

不能移动的

不可移动的接口和ImmovableImpl实现:

type Immovable interface {
    Object
    immovable()
}
type ImmovableImpl struct {
    ObjectImpl // Embed ObjectImpl
}
func (o *Immovable) immovable() {}

注意ImmovableImpl只添加immovable()方法,object()是“继承”.

建造

建筑实施:

type Building struct {
    ImmovableImpl // Embed ImmovableImpl struct

    // Building-specific other fields may come here
}

注意Building不会添加任何新方法,但它会自动成为Immovable对象.

如果“子类型”的数量增加或者接口类型具有多于1个“标记”方法(因为所有方法都是“继承的”),这种技术的优势会大大增加.

相关文章
相关标签/搜索