猿问

带结构的循环导入

我在 Go 中有一个包含多个模块的项目。由于以下情况,我遇到循环导入问题:

细节

一个模块 Game 包含一个具有当前 Game 状态的结构体。另一个模块(修改器)正在做一些游戏特定的东西和计算,因此修改游戏状态。因此,Modifier 将需要结构体 Game,但不需要 Game 中的任何方法。Modifier 是从 Game 中调用的,这里我们有循环导入。

问题:

  • 游戏启动修改器

  • 修改器需要游戏结构

在我看来,这是一个常见的情况,所以我想知道我应该如何以最好的方式解决它。我的解决方案是创建第三个模块“Structs”,它只包含整个应用程序的所有结构。这是一个很好的解决方案吗?


慕哥6287543
浏览 181回答 3
3回答

ABOUTYOU

使用第三个套餐选项:yourgame/  state/    state.go  modifier/    modifier.go  main.gomain.go 将两个组件粘合在一起:import "yourgame/state"import "yourgame/modifier"type Game struct {    state    state.State    modifier modifier.Modifier}func main() {    // something like:     var game Game    game.modifier.Modify(game.state)}不过,这种方法可能过于紧密耦合。与其操作本质上是全局的状态对象,不如尝试将数据分割成修改器所需的数据。抽象的推理很难,所以这里有一个具体的例子来说明我的意思。在你的游戏中:type Object struct {    ID, X, Y int    // more data here}type Game struct {    Objects map[int]*Object}在您的“修改器”中,假设我们有一个移动对象的 AI 模块。如果他只关心单个对象的位置,您可以创建一个界面:// in yourgame/modifiertype Object interface {    GetCoordinates() (int, int)    SetCoordinates(int, int)}type Modifier struct {}func (m *Modifier) Update(obj Object) { }然后我们只需要将这些方法添加到我们的原始对象中:type (obj *Object) GetCoordinates() (int, int) {    return obj.X, obj.Y}type (obj *Object) SetCoordinates(x, y int) {    obj.X, obj.Y = x, y}现在您可以将对象传递给您的修改器,而无需循环依赖。现在,如果事实证明您的“修改器”界面最终看起来与您的游戏对象几乎完全相同,那么第三个结构包可能是合理的,因此您不必总是重复自己。例如,考虑net/url.

慕容3067478

通常,如果 packageB有直接读取/修改的代码,A.Type那么该代码应该在 package 中A。至少需要直接访问的部分应该是。要在单独的包之间拆分某些内容A,B您通常会尝试隔离 API 以访问A.Type可以表示为接口的 API 。然后B将定义和使用这个接口并A.Type实现它(隐式地,不需要包含 B 对它的定义)。然后一些东西(可能A,可能是一个单独的包)将B通过适当地传递一个A.Type或*A.Type值来使用。或者,根据您的设计,这种关系可以颠倒,B.OtherType隐式实现由A. 或两者A并B只能通过接口使用对方; 这一切都取决于细节。例如,也许是这样的:package Game // "A"type State struct {        data int // etc}func (s State) IsValid() bool          { return true }func (s *State) ChangeY(arg int) error { return nil }// …etc…和:package Modifier // "B"type GameState interface {        IsValid() bool        ChangeY(int) error}type M struct {        s GameState        //…}func New(s GameState) *M {        return &M{s: s}}func (m M) DoSomething() {        if s.IsValid() {                // …        }        s.ChangeY(42)        // …etc…}

神不在的星期二

我会在同一个包中定义类型(在这种情况下是游戏)及其所有方法。你甚至不能根据语言规范定义从另一个包导入的类型的方法,//you should first do type MyPackageType ImportedType//and only thenfunc (foo MyPackageType) Modify() {...}
随时随地看视频慕课网APP

相关分类

Go
我要回答