当前位置: 首页 > 面试题库 >

Go创建复杂的结构层次结构的惯用方式是什么?

长孙文栋
2023-03-14
问题内容

我在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编译器如何使用许多空方法来实现
AST的方式。但为什么?注意定义了多少个空方法。随着层次结构深度的增加,它可能会变得非常复杂。

注释中指出,空方法禁止分配不兼容的类型。在我们的示例中,*Car不能将a分配给*Immovable例如。

在其他支持继承的语言(例如C ++)中,这是如此容易。我想不出代表AST的任何其他方式。

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


问题答案:

Go 不是(相当)一种面向对象的语言:它没有类,也没有类型继承。但它支持类似的构造,称为在层和层上
嵌入
,并且确实具有方法。struct``interface

Go中的接口只是固定的方法集。如果类型的方法集是该接口的超集(没有意图的声明),则该类型
隐式 实现接口。

如果要 明确 记录声明
您的类型确实实现了接口(因为未明确声明),则空方法非常有用。官方Go常见问题解答:如何保证我的类型满足界面要求?

type Fooer interface {
    Foo()
    ImplementsFooer()
}

如果你想在你的类型层次区分(例如,你不想让一个对象既MovableImmovable),它们必须有不同的方法集(必须有至少1方法在每个方法集的MovableImmovable是不存在于另一个Movable变量中),因为如果方法集将包含相同的方法,那么一个方法的实现也会自动实现另一个方法,因此您可以将一个对象分配给type变量Immovable

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

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

如果您还为层次结构中的每种类型创建一个struct 实现 ,并且每个实现 实现 嵌入
struct更高一级,则更高级别的方法集将自动出现,而无需费心:

目的

Object接口和ObjectImpl实现:

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

不动产

Immovable接口和ImmovableImpl实现:

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

注意ImmovableImpl仅添加immovable()方法,object()是“继承”的。

建造

Building 实施:

type Building struct {
    ImmovableImpl // Embed ImmovableImpl struct

    // Building-specific other fields may come here
}

注意Building 不会添加 任何新方法,但它自动是一个Immovable对象。

如果“子类型”的数量增加或接口类型具有不止一种“标记”方法(因为“继承”了所有方法),则该技术的优势将大大增加。



 类似资料:
  • 问题内容: 我需要验证结构值是否正确,这意味着我需要单独检查每个字段,这对于少量的小型结构来说很容易,但是我想知道是否有更好的方法。这就是我现在的做法。 这是验证结构中字段值的惯用方式吗?看起来很麻烦。 问题答案: 我认为没有其他方法可以快速完成此操作。但是我找到了一个可以帮助您的go软件包:https : //github.com/go- validator/validator README文件

  • 在Tableau中,可以构建层次结构以可视化数据。可以通过以下步骤在Tableau中创建它: 例如,考虑数据源,例如Sample-Superstore,以及它的维度和度量。 第1步: 首先转到工作表。然后, 选择一个维度,然后右键单击该维度以创建层次结构。 转到“层次结构(Hierarchy)”选项。 并且,单击下面屏幕截图中显示的“创建层次结构(Create Hierarchy)”选项。 第2步

  • 我在我的应用程序中使用MVVM模式。我有以下(简化版)VM类: 因此,一个Module2601_VM包含几个属性,以及Module2610_VM和ComPort_VM对象的列表。 我有一个MainModule_VM类中Module2601_VM对象的列表。 我想将这个Module2601集合及其子项绑定到树状视图中,并使用以下层次结构: 网关: 网关#0 COM#1 我的问题是,我的层次结构正常,

  • 本文向大家介绍使用递归[JavaScript]创建层次结构,包括了使用递归[JavaScript]创建层次结构的使用技巧和注意事项,需要的朋友参考一下 示例 输出            

  • 问题内容: 是否可以基于层次结构/ cte创建视图? 我看过一个有关如何基于链接递归查询生成结果集的示例。 我已经附上了ddl和声明。 谢谢你, 埃尔默 问题答案: 后已被指定(超出右括号),您需要选择从CTE的所有值: 这是构成视图的实际选择查询。 这是一个完整的工作示例,其中选择了视图的最终输出,以及一些其他语句,以允许这些语句在SQL Server Management Studio中一次执

  • 在Spring-boot应用程序中使用yaml(带有snakeyaml依赖关系1.16),我试图基于application.yml文件创建。我想创建一个像下面的json这样的数据结构,它是一个包含字符串键和数组值的映射。 我已经为我的yaml尝试了以下方法 尝试二 尝试三 如果我将集合更改为一个ArrayList(或List接口),这就可以了,但这不是我想要的。更改为此 但need也不能用于Set