为什么 go 不支持循环引用

3,121 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

什么是循环引用?

循环引用是 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 程序员更多的考虑程序的依赖关系,保持依赖关系图的整洁

  • 同时可以使项目快速构建。

循环引用有什么弊端?

首先,循环引用肯定会导致缓慢的程序构建。

其次,如果项目中存在循环引用,那么模块和模块之间就存在相互的调用,随着项目的推进,模块之间的依赖关系会越来越多,最后导致两个模块耦合性变得越来越高,最初之间的界限变得越来越模糊,最后都耦合在一起,变得一团糟。

另外,循环引用还有可能会导致无限递归,继而引发其它问题。

如何避免循环引用?

很重要的一点是:设计好代码结构!!!

参考文档