解决 Go 中循环依赖的最佳实践

Wil*_* M. 6 circular-dependency go

我有一个包含这两个包的 Go 项目:

  • logging
    Imports config,因为我想将当前配置发送到我的错误报告系统
  • config
    Imports logging,因为我想记录程序是否无法打开配置文件

解决此依赖性错误的最佳实践是什么?

mko*_*iva 9

您以什么格式将配置发送到错误报告系统?也许将其传递给日志记录?比如说,如果它是 json,则在将其提供给日志记录之前对配置进行编组,然后[]byte仅将结果提供给日志记录。

但一般来说,如果两个包直接相互依赖,您可以做的就是让其中一个包声明一个与另一个包的行为相匹配的接口,然后让一个单独的包将具体实例作为接口传递。

例如:

/myapp/config

import "myapp/logging"

type Config struct {
     // ...
}

func NewConfig() *Config {
    // ...
    if err != nil {
        logging.LogError(err)
    }
}
Run Code Online (Sandbox Code Playgroud)

/myapp/logging

import "myapp/config"

func LogConfig(c *config.Config) {
    // ...
}

func LogError(err error) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下,您可以在配置包中声明一个与日志记录所需的行为相匹配的接口。

/myapp/config

type Logging interface {
    LogError(error)
}

var logging Logging

func SetLogging(l Logging) {
    logging = l
}

type Config struct {
     // ...
}

func NewConfig() *Config {
    // ...
    if err != nil {
        logging.LogError(err)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后让日志记录包中的类型通过简单地委托给原始函数来实现该接口。

/myapp/logging

import "myapp/config"

func LogConfig(c *config.Config) {
    // ...
}

func LogError(err error) {
    // ...
}

type Logging struct{}

func (Logging) LogError(err error) {
    LogError(err)
}
Run Code Online (Sandbox Code Playgroud)

最后还有第三个包,使其能够协同工作。

/myapp

import "myapp/config"
import "myapp/logging"

func init() {
    config.SetLogging(logging.Logging{})
}
Run Code Online (Sandbox Code Playgroud)