小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
什么是循环引用?
循环引用是 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 程序员更多的考虑程序的依赖关系,保持依赖关系图的整洁;
-
同时可以使项目快速构建。
循环引用有什么弊端?
首先,循环引用肯定会导致缓慢的程序构建。
其次,如果项目中存在循环引用,那么模块和模块之间就存在相互的调用,随着项目的推进,模块之间的依赖关系会越来越多,最后导致两个模块耦合性变得越来越高,最初之间的界限变得越来越模糊,最后都耦合在一起,变得一团糟。
另外,循环引用还有可能会导致无限递归,继而引发其它问题。
如何避免循环引用?
很重要的一点是:设计好代码结构!!!