关于如何避免Go中的导入周期的任何好建议?

Rec*_*Hou 41 dependencies circular-dependency go

我正在研究Go项目一个月.好的是Go非常高效.但经过一个月的开发,我已经有了数千行代码和许多代码packages.为了避免导入周期对我来说是一个主要的问题,任何时候我遇到导入周期错误,我不知道第一次问题可能在哪里.

Go编译器也只有非常简单的通知,总是不能很好地快速定位问题,如:main.go:7:3: import cycle not allowed.它只会帮助您了解哪个文件可能导致问题,但不会更深入.由于import关系在代码增长时变得越来越复杂,我迫切希望知道如何在Go中更有效地避免导入周期.任何帮助深表感谢.

zzz*_*zzz 58

go list -f '{{join .Deps "\n"}}' <import-path>
Run Code Online (Sandbox Code Playgroud)

将显示包的导入依赖关系<import-path>- 如果<import-path>保留为空,则显示当前目录中的导入依赖关系.另外

go list -f '{{join .DepsErrors "\n"}}' <import-path>
Run Code Online (Sandbox Code Playgroud)

希望在您的案例中显示一些有用的信息.另见输出

go help list
Run Code Online (Sandbox Code Playgroud)

有关go list工具的其他信息.

  • 绝对好知道,实际上甚至都不知道去列表. (3认同)

mna*_*mna 42

为了补充jnml的答案(这有助于"调试"循环引用问题),你可以使用依赖性反转来打破这些循环,再加上依赖注入.对于一个应用程序,我总是尝试遵循Clean Architecture的指导- 请参阅这里的Go特定示例 - 我发现Go的"非声明性实现"接口(也就是说,您不必明确说出type MyStruct struct implements IfceSomething)使这很简单.

所以,如果你有软件包A -> B -> C -> A,你InterfaceA在软件包C中创建(一些相关名称,显然,与包相关的行为相关:),并使其依赖于此接口而不是软件包A,并确保软件包A"实现"这个界面.

然后你必须在某些时候提供A到C的具体实现(这里有很多可能性,我通常在知道所有依赖关系的主包中执行这个"粘合"代码).


小智 8

由于导入关系在代码增长时变得越来越复杂,我迫切希望知道如何在Go中更有效地避免导入循环.

另一种选择是可视化项目中的依赖项.这可以使用CLI工具godepgraph完成.你可以安装它:

go get -u github.com/kisielk/godepgraph
Run Code Online (Sandbox Code Playgroud)

然后使用它在另一个CLI工具graphvis的帮助下在您的应用程序中查找导入周期.使用此工具可以可视化包依赖关系:

godepgraph -s path/to/my/package | dot -Tpng -o godepgraph.png
open ./godepgraph.png
Run Code Online (Sandbox Code Playgroud)

在我的代码中查找循环: 在此输入图像描述