什么是循环引用?
循环引用是 go 语言开发工程师经常会遇到的一个问题。所谓的循环引用,就是在 A 包中引用 B 包,B 包引入 C 包,而在 C 包中又引入了 A 包,在项目编译时,就会报循环引用错误,注意是错误而非警告。
我们要实际演示一下:talk is easy, show me the code
。
我们定义三个文件 HelloA,HelloB 和 HelloC。
package A import ( "fmt" "go_learn/C" ) func HelloA() { C.HelloC() fmt.Println("package A hello") }
package B import ( "fmt" "go_learn/A" ) func HelloB() { A.HelloA() fmt.Println("package B hello") }
package C import "C" import ( "fmt" "go_learn/B" ) func HelloC() { B.HelloB() fmt.Println("package C hello") }
package main import ( "go_learn/A" ) func main() { A.HelloA() }
然后执行一下 main 函数,发现抛如下错误:
package go_learn imports go_learn/A imports go_learn/C imports go_learn/B imports go_learn/A: import cycle not allowed
由此可见,循环引用在 go 中被归结为错误!
为什么 go 不支持循环引用?
对于这个问题,Go 语言之父 Rob Pike 曾做过解答,他认为:
循环引用的代码设计是不合理的,没有很好的考虑代码的结构;
*没有支持循环引用,目的是迫使 Go 程序员更多的考虑程序的依赖关系,保持依赖关系图的整洁;*
同时可以使项目快速构建。
循环引用有什么弊端?
首先,循环引用肯定会导致缓慢的程序构建。
其次,如果项目中存在循环引用,那么模块和模块之间就存在相互的调用,随着项目的推进,模块之间的依赖关系会越来越多,最后导致两个模块耦合性变得越来越高,最初之间的界限变得越来越模糊,最后都耦合在一起,变得一团糟。
另外,循环引用还有可能会导致无限递归,继而引发其它问题。
如何避免循环引用?
很重要的一点是:设计好代码结构!!!