带结构的循环导入 [英] Circular import with structs

查看:75
本文介绍了带结构的循环导入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Go中有一个包含多个模块的项目.由于以下情况,我在循环进口方面遇到了问题:

I have a project with several modules in Go. I am having problem with circular imports because of the scenario below:

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

A module Game contains a struct with the current Game state. Another module (Modifier) is doing some game specific stuff and calculations and therefore modifies the game state. Because of this, Modifier will need the struct Game, but not any methods from Game. Modifier is called from Game and here we have the circular import.

  • 游戏启动修改器

  • Game initiates Modifier

修饰符需要游戏结构

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

It seems to me that this is a common scenario, so I wonder how I should solve it in the best way. My solution would be to create a third module "Structs" which just contains all the structs for the whole application. Is this a good solution?

推荐答案

使用第3个软件包选项:

With the 3rd package option:

yourgame/
  state/
    state.go
  modifier/
    modifier.go
  main.go

main.go 会将两个组件粘合在一起:

main.go would glue the two components together:

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)
}

这种方法可能太紧密了.与其操纵基本的全局状态对象,不如尝试将数据切成所需的修饰符.

This approach is probably too tightly coupled though. Rather than manipulating an essentially global state object, I would try to slice up the data into just what you need for the modifier.

要进行抽象推理很困难,所以这是我的意思的一个具体例子.在您的游戏中:

Reasoning in the abstract is hard, so here's a concrete example of what I mean. In your game:

type Object struct {
    ID, X, Y int
    // more data here
}
type Game struct {
    Objects map[int]*Object
}

在您的修饰符"中,假设我们有一个用于移动对象的AI模块.如果他只关心单个对象的位置,则可以创建一个接口:

In your "modifier", let's suppose we had an AI module that moves an object. If all he cares about is the position of a single object you can create an interface:

// in yourgame/modifier
type Object interface {
    GetCoordinates() (int, int)
    SetCoordinates(int, int)
}
type Modifier struct {}
func (m *Modifier) Update(obj Object) { }

然后我们只需将这些方法添加到原始对象中即可:

Then we just have to add those methods to our original 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
}

现在您可以将对象传递到修饰符,而无需循环依赖.

And now you can pass objects to your modifier without needing a cyclic dependency.

现在,如果事实证明您的修饰符"界面看起来与游戏对象几乎完全相同,那么第3种结构包可能是合理的,因此您不必总是重复自己.例如,请考虑 net/url .

Now if it turns out your "modifier" interface ends up looking almost exactly the same as your game object, then a 3rd package of structs is probably reasonable so you aren't always repeating yourself. For an example consider net/url.

这篇关于带结构的循环导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆