Golang Go语言中请教下用这种方式解决 import cycle 有什么弊端吗?

发布于 1周前 作者 wuwangju 来自 Go语言
package a

import ( “fmt” “cc/c” )

func Out() { fmt.Println(c.GetB()) }

func GetA() string { return “a” }

func init() { c.GetA = GetA }

package b

import (
	"fmt"
	"cc/c"
)

func Out() {
	fmt.Println(c.GetA())
}

func GetB() string{
	return "b"
}

func init() {
	c.GetB = GetB
}
package c

var GetA func()string
var GetB func()string

就是 a 和 b 在 init 的时候, 向 c 注册, c 不引任何包, 这样的做有什么问题吗?


Golang Go语言中请教下用这种方式解决 import cycle 有什么弊端吗?

更多关于Golang Go语言中请教下用这种方式解决 import cycle 有什么弊端吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

10 回复

你这个难道能编译通过? GetA 不是一个函数吗,你怎么能给函数赋值?

更多关于Golang Go语言中请教下用这种方式解决 import cycle 有什么弊端吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


GetA 看着是个函数指针啊?😯

可以是可以,但是你未来很难保证你的这个包只有函数和基本类型吧

是的, 但是包里有几个方法很难再拆包了, 社交的业务代码比较杂乱, 暂时采取这种丑陋的方式

也许不用写这么复杂,这不就是个全局变量吗?
用全局变量解决 import cycle 好吗?不好

我上面写的办法应该跟 cockroachdb 的 Dependency injection 的方案是类似的 :)

所以也一直觉得比较丑陋, 但是更好的办法也还没找到

我想到的三种做法,越往后的越好
1. 包下拆分子包,a 引入 a 下的子包 c ,b 作为与 a 同级别包也引入 a 包下的子包 c ; c 内尽量保持简洁不额外依赖,很多 model 包会这么做
2. 使用 wire 或者类似依赖注入的方案 ,https://github.com/google/wire ,wire 将所有依赖按照 hierarchy 汇总成一个 Application ,向面向对象一样,方法调用时尽量调用 Method 而不是 Function
3. 在 2. 的基础上拆分业务逻辑,面向接口编程,向 5 楼发的一样,将一些类似的业务逻辑提取成 Interface ,a 包 b 包皆依赖于 c 包中的 Interface ,而不必关心相互是否实现

另外,还是尽量避免使用 init 吧

在Go语言中,处理import cycle(循环依赖)确实是一个需要谨慎对待的问题。循环依赖通常表明代码设计存在问题,它会导致编译失败,因为Go编译器不允许存在无法解决的依赖链。

针对你提到的“这种方式”解决import cycle,虽然你没有具体说明是哪种方式,但一般来说,常见的解决方法包括:

  1. 重构代码:将共享的功能或数据结构提取到一个新的包中,这个新包不应该依赖于其他产生循环依赖的包。这是最优雅且推荐的方式,因为它能从根本上解决问题,同时保持代码的清晰和模块化。

  2. 使用接口:通过定义接口来解耦依赖关系。具体实现类可以不直接依赖于其他包,而只依赖于接口定义。这样可以在一定程度上缓解循环依赖的问题,但可能需要更多的抽象和间接性。

  3. 避免全局变量和单例模式:这些模式容易引入不必要的依赖关系,导致循环依赖问题。

然而,任何试图绕过编译器检查直接解决循环依赖的“技巧”或“方式”都可能带来潜在的维护问题。例如,它可能使代码更难理解和测试,甚至在未来引入难以追踪的bug。因此,建议优先考虑上述的正规解决方法,而不是寻求快速但可能不稳定的“捷径”。

总之,解决import cycle的关键在于良好的代码设计和模块化,而非临时性的解决方案。

回到顶部