将程序拆分为子包后,Golang“不允许导入循环”

时间:2017-08-10 09:09:32

标签: go

我有一个很大的Go程序,它分布在我的包文件夹根目录中的50多个杂项Go文件中。我知道这被认为是可怕的,所以我决定将程序拆分成一些子包以便更好地组织。

不幸的是,在将程序的逻辑部分拆分为子包之后,我遇到了可怕的“导入循环不允许”错误。这是因为Go编译器拒绝使用循环导入编译任何内容。但是我的程序的不同逻辑部分需要相互通信......

我在网上做了一些研究,发现了一些优秀的资源,比如this excellent StackOverflow question,试图解释在高层次上解决这个问题的想法。

我很抱歉,但是这篇文章已经超出了我的想法,我想知道是否有人可以为我的特定代码情况拼出一个确切的解决方案,希望用更简单的语言来完成初学者Go。

我的代码组织方式及其作用的简要说明:

  • 它使用3种不同的协议(Twitch.tv,Discord和自定义WebSocket服务器)连接到3个不同的服务器。
  • 很明显,制作3个子包,每个服务器类型一个,然后在main.go文件中初始化所有这些子包。
  • 每个子包不仅仅是一个接口;它包含一组全局变量(跟踪连接+其他事物)和一堆函数。 (请注意,如果需要,我可以重构它,使其全部包含在一个巨大的接口中。)
  • 95%的时间,子包从各自的服务器接收消息并将消息发送回各自的服务器,因此子包大多是分区的。
  • 但是,有时Twitch.tv模块需要向Discord服务器发送消息,而Discord服务器需要向Twitch.tv服务器发送消息。所以Discord服务器需要能够调用Twitch.tv子包内的“Send()”函数,而Twitch.tv子包需要能够调用Discord子包的“Send()”函数!所以这就是我的循环问题所在。

4 个答案:

答案 0 :(得分:2)

看起来您希望将协议特定代码保存在单独的包中。 如果您不想要太多重构,我建议您使用dispatcher创建一个包。每个服务器都导入dispatcher包并注册特定协议的处理程序。当需要调用另一台服务器时,只需通过dispatcher向指定的处理程序发送消息。

答案 1 :(得分:1)

根据您的具体情况量身定制:

根据您的描述,程序包相互导入的唯一原因是他们需要相互调用Send()函数。

沟通渠道

在main中创建频道,并将其提供给init上的两个软件包。然后他们可以在不知道彼此存在的情况下相互沟通。

答案 2 :(得分:1)

除了TechSphinX和Oleg提出的基于通道的方法之外,您还可以使用基于接口的方法和简单的依赖注入。

您可以使用可能在main()中或从Send()调用的设置功能来创建每个服务客户端的实例。这些应该每个都实现Sender并为他们需要使用的其他客户端提供字段。在自己的包中创建一个// pkg sender type Sender interface { Send(m Message) error // or whatever it needs to be } type Message struct { // Whatever goes in a message } type Dispatcher struct { TwitchClient Sender DiscordClient Sender WebClient Sender } // pkg main func setup() { d := sender.Dispatcher{ TwitchClient: twitch.New(), DiscordClient: discord.New(), WebClient: web.New(), } d.TwitchClient.Dispatcher = d d.DiscordClient.Dispatcher = d d.WebClient.Dispatcher = d } // pkg twitch type TwitchClient struct { Dispatcher sender.Dispatcher // other fields ... } func New() *TwitchClient { return new(TwitchClient) // or whatever } func (t *TwitchClient) Send(m sender.Message) error { // send twitch message... // Need to send a Discord message? t.Dispatcher.DiscordClient.Send(m) } 接口,并将消息结构放在那里。

创建实例后,您可以在每个实例上设置其他客户端。通过这种方式,他们可以发送到他们需要发送的任何内容,而不需要循环依赖。您甚至可以将所有客户端放入结构中以使注入更容易。

例如:

@Autowired
ServletContext context;

答案 3 :(得分:1)

听起来服务器/协议包本身很有用,并且要求将消息从一种服务器发送到另一种服务器是您特定应用程序的一项功能。换句话说,服务器/协议包不需要彼此发送消息,应用程序需要。

我通常会将特定于应用程序的功能放入应用程序包中。包应用可以导入所有协议包。

您也可以在主程序包中执行此操作,但我发现应用程序包是更有用的工具。 (我的主要包通常只是单个main.go文件。)