一、go中為什么不允許循環(huán)依賴
二、如何解決循環(huán)依賴
循環(huán)依賴就是A引用B,B又引用A,形成了一個包引用的閉環(huán)。要解決循環(huán)引用,就是打破這個閉環(huán),讓A引用B,B不能引用A??聪旅娴睦樱?/p>
包結構如下:

package bagA
import (
"fmt"
"gotest/test/go_basic/problem_record/bag_circle_import/bagB"
)
func GetName()string{
return "bag A"
}
func PrintA(){
fmt.Println(fmt.Sprintf("I am bag A, and %s is bag B", bagB.GetName()))
}
package bagB
import (
"fmt"
)
func GetName()string{
return "bag B"
}
func PrintB(){
fmt.Println(fmt.Sprintf("I am bag B, and %s is bag A", AHandler()))
}
package main
import "gotest/test/go_basic/problem_record/bag_circle_import/bagA"
func main(){
bagA.PrintA()
}
執(zhí)行main函數(shù)報錯:

報錯的原因是 我們在執(zhí)行bagA.PrintA()的時候,引用了A包,A包又引用了B包,B包又引用了A包,形成了循環(huán)依賴。那我們打破依賴就可以了。
那么該怎么打破呢?
我們發(fā)現(xiàn)A包引用B包,是因為A包需要調(diào)用B包的bagB.GetName()方法;同樣的,B包引用A包,是因為B包需要調(diào)用A包的bagA.GetName()方法。那么,我們有沒有不需要引包就能使B包可以調(diào)用A包的方法呢?
當然是有的??聪旅妫?/p>
package bagA
import (
"fmt"
"gotest/test/go_basic/problem_record/bag_circle_import/bagB"
)
func init(){
bagB.Register(GetName)
}
func GetName()string{
return "bag A"
}
func PrintA(){
fmt.Println(fmt.Sprintf("I am bag A, and %s is bag B", bagB.GetName()))
}
package bagB
import (
"fmt"
)
func GetName()string{
return "bag B"
}
func PrintB(){
fmt.Println(fmt.Sprintf("I am bag B, and %s is bag A", AHandler()))
}
var AHandler func()string
func Register(f func()string){
AHandler = f
}
我們在B包里定義了一個方法變量AHandler,并且提供了為這個方法變量賦值的方法Register(),然后在A包里的init()方法里,調(diào)用B包的Register()方法,將A包的GetName方法復賦值給了AHandler變量。 這樣,在B包執(zhí)行方法AHandler是不是就相當于調(diào)用了A包的GetName方法呢?看執(zhí)行結果:

總結:
上述解決辦法的核心邏輯就是,B包使用一個方法變量來替代A中的方法(來完成B不引用A),A來為該變量賦值(因為A引用B,A可以調(diào)用B的方法來完成賦值)。 解決循環(huán)依賴問題,思想就是打破包的循環(huán)依賴,以不導包的方式調(diào)用其他包的方法。所以,采用接口的形式也可以解決循環(huán)依賴(B定義一個接口,A中你想要調(diào)用的方法實現(xiàn)了該接口,A中完成接口變量賦值,B來調(diào)用接口方法,有時間再補充例子吧)