2025-02-15 05:00:06

不允许导入周期

我有个问题

不允许导入周期

它出现在我试图测试我的控制器时。输出如下:

can't load package: import cycle not allowed
package project/controllers/account
    imports project/controllers/base
    imports project/components/mux
    imports project/controllers/account
import cycle not allowed
package project/controllers/account
    imports project/controllers/base
    imports project/components/mux
    imports project/controllers/account
import cycle not allowed
package project/controllers/account
    imports project/controllers/base
    imports project/components/mux
    imports project/controllers/routes
    imports project/controllers/base

如何阅读或理解此错误?依赖关系错在哪里?


当前回答

这是一个循环依赖问题。Golang程序必须是无循环的。在Golang中,循环导入是不允许的(即它的导入图必须不包含任何循环)

假设你的项目循环依赖有两个包“包一”和“包一”。选择“&”“package two”,它有“two”。你的项目结构是这样的

+--go-circular-dependency    
      +--one    
         +-one.go
      +--two        
         +-two.go

当您尝试执行以下操作时,会出现此问题。

第一步——一步到位。你导入包2(下面是一个。go)

package one

import (
    "go-circular-dependency/two"
)

//AddOne is
func AddOne() int {
    a := two.Multiplier()
    return a + 1
}

第二步——两步。你导入包1(下面是2 .go)

package two

import (
    "fmt"
    "go-circular-dependency/one"
)

//Multiplier is going to be used in package one
func Multiplier() int {
    return 2
}

//Total is
func Total() {
    //import AddOne from "package one"
    x := one.AddOne()
    fmt.Println(x)
}

在第2步,你会收到一个错误“不能加载包:导入周期不允许” (这被称为“循环依赖”错误)

从技术上讲,这是一个糟糕的设计决策,你应该尽可能地避免这种情况,但你可以“通过隐式接口打破循环依赖”(我个人不建议,也非常不鼓励这种做法,因为在设计上Go程序必须是非循环的)

尽量使导入依赖关系保持浅层。当依赖关系图变得更深(即包x导入y, y导入z, z导入x)时,循环依赖关系变得更有可能。

有时候代码重复并不是一个坏主意,这与DRY完全相反(不要重复自己)

第2步是2。你不应该导入第一个包。而是两个。你应该复制AddOne()的功能写在一个。按照下面的步骤进行。

package two

import (
    "fmt"
)

//Multiplier is going to be used in package one
func Multiplier() int {
    return 2
}

//Total is
func Total() {
    // x := one.AddOne()
    x := Multiplier() + 1
    fmt.Println(x)
}

其他回答

我得到了另一个解。

我的情况

我发现在开始项目工作之前,我没有运行命令:go mod init <module_name>。 后来我试图导入“mux”包去获得github/gorilla/mux,然后我得到了错误“导入周期不允许”。

如果需要,检查您正在工作的目录中是否已经初始化了模块(pt 1.中提到的命令)。然后尝试运行脚本。

该错误是由两个模块同时导入而导致的。

Module A importing Module B
Module B importing Module A

解决方案:想办法把双向导入变成单向导入。

这是一个循环依赖问题。Golang程序必须是无循环的。在Golang中,循环导入是不允许的(即它的导入图必须不包含任何循环)

假设你的项目循环依赖有两个包“包一”和“包一”。选择“&”“package two”,它有“two”。你的项目结构是这样的

+--go-circular-dependency    
      +--one    
         +-one.go
      +--two        
         +-two.go

当您尝试执行以下操作时,会出现此问题。

第一步——一步到位。你导入包2(下面是一个。go)

package one

import (
    "go-circular-dependency/two"
)

//AddOne is
func AddOne() int {
    a := two.Multiplier()
    return a + 1
}

第二步——两步。你导入包1(下面是2 .go)

package two

import (
    "fmt"
    "go-circular-dependency/one"
)

//Multiplier is going to be used in package one
func Multiplier() int {
    return 2
}

//Total is
func Total() {
    //import AddOne from "package one"
    x := one.AddOne()
    fmt.Println(x)
}

在第2步,你会收到一个错误“不能加载包:导入周期不允许” (这被称为“循环依赖”错误)

从技术上讲,这是一个糟糕的设计决策,你应该尽可能地避免这种情况,但你可以“通过隐式接口打破循环依赖”(我个人不建议,也非常不鼓励这种做法,因为在设计上Go程序必须是非循环的)

尽量使导入依赖关系保持浅层。当依赖关系图变得更深(即包x导入y, y导入z, z导入x)时,循环依赖关系变得更有可能。

有时候代码重复并不是一个坏主意,这与DRY完全相反(不要重复自己)

第2步是2。你不应该导入第一个包。而是两个。你应该复制AddOne()的功能写在一个。按照下面的步骤进行。

package two

import (
    "fmt"
)

//Multiplier is going to be used in package one
func Multiplier() int {
    return 2
}

//Total is
func Total() {
    // x := one.AddOne()
    x := Multiplier() + 1
    fmt.Println(x)
}

下面是第一个导入周期问题的示例。

                  project/controllers/account
                     ^                    \    
                    /                      \
                   /                        \ 
                  /                         \/
         project/components/mux <--- project/controllers/base
            
                   

正如你在我的坏ASCII图中看到的,当project/components/mux导入project/controllers/account时,你创建了一个导入循环。因为Go不支持循环依赖,所以在编译时你会得到导入周期不允许的错误。

我刚刚遇到了这个。您可以使用包名本身从同一个包中访问一个方法/类型。

下面是一个例子来说明我的意思:

在foo.go:

// foo.go
package foo

func Foo() {...}

在foo_test.go:

// foo_test.go
package foo

// try to access Foo()
foo.Foo() // WRONG <== This was the issue. You are already in package foo, there is no need to use foo.Foo() to access Foo()
Foo() // CORRECT

循环依赖的另一个常见原因显示在这个答案中。

与JavaScript不同,Go对循环依赖的容忍度很低,这是好事也是坏事。