为了账号安全,请及时绑定邮箱和手机立即绑定

带结构的循环导入

带结构的循环导入

Go
慕哥6287543 2021-10-04 15:59:00
我在 Go 中有一个包含多个模块的项目。由于以下情况,我遇到循环导入问题:细节一个模块 Game 包含一个具有当前 Game 状态的结构体。另一个模块(修改器)正在做一些游戏特定的东西和计算,因此修改游戏状态。因此,Modifier 将需要结构体 Game,但不需要 Game 中的任何方法。Modifier 是从 Game 中调用的,这里我们有循环导入。问题:游戏启动修改器修改器需要游戏结构在我看来,这是一个常见的情况,所以我想知道我应该如何以最好的方式解决它。我的解决方案是创建第三个模块“Structs”,它只包含整个应用程序的所有结构。这是一个很好的解决方案吗?
查看完整描述

3 回答

?
ABOUTYOU

TA贡献1812条经验 获得超5个赞

使用第三个套餐选项:


yourgame/

  state/

    state.go

  modifier/

    modifier.go

  main.go

main.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/modifier

type 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.


查看完整回答
反对 回复 2021-10-04
?
慕容3067478

TA贡献1773条经验 获得超3个赞

通常,如果 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…

}


查看完整回答
反对 回复 2021-10-04
?
神不在的星期二

TA贡献1963条经验 获得超6个赞

我会在同一个包中定义类型(在这种情况下是游戏)及其所有方法。你甚至不能根据语言规范定义从另一个包导入的类型的方法,


//you should first do 

type MyPackageType ImportedType

//and only then

func (foo MyPackageType) Modify() {

...

}


查看完整回答
反对 回复 2021-10-04
  • 3 回答
  • 0 关注
  • 180 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信