这个问题出现在写项目中遇到的问题,即包的环状引用,引入Listener机制可以解决这个问题,其实这个解决方案也可以扩展至其他语言。
其实问题的描述很容易,就是两个包之间互有引用,当然最好 的解决方案就是在设计的时候可以考虑到这个问题,从而在设计阶段就避免这个问题,但不是每个人都可以在设计阶段看的那么深的,所以在出现这个问题的时候我们需要一种机制解决这个问题,其实就是一种特殊的回调机制。
package A testA.go func LoadServerConfig(filename string, cfg *Connect.ServerConfig) bool{ .... } func init(){ Connect.RegisterRestServerListener(LoadServerConfig) } package B testB.go type ServerConfig struct{ ... } type ServerListener func(filename string, cfg *ServerConfig) bool var ServerListeners []ServerListener func RegisterRestServerListener(l ServerListener) { ServerListeners = append(ServerListeners, l) }我们可以清楚的看到A包中包含了B包中的ServerConfig,B包中又要使用LoadServerConfig,此时就会出现环状引用,解决方案就是引入一个ServerListeners,在A包的init函数中把LoadServerConfig当做一个回调调用RegisterRestServerListener放入ServerListeners,此时B包中就不必直接调用B包中的LoadServerConfig了,直接调用ServerListeners中的回调就OK了,但是在需要调用B包的地方我们也要引入A包,并在import后面加上_,代表执行包中的init函数,这样才可以把A包的函数挂到B包。
其实还有一种方法,就是[1]中的方法,但是我个人认为其实都差不多,没有太搞懂其中指针转来转去是什么意思,以为写了一个简单的测试代码可以看出转不转都是可以跑通的。
package test_cycle_a import ( "fmt" "hello/test_cycle_b" ) func init() { str := "hello world" test_cycle_b.Test(str, rocketfunction) } func rocketfunction(str string) { fmt.Println("hello : " ,str) } package test_cycle_b import ( "fmt" "strconv" "unsafe" ) type Callback func(str string) var Fun Callback func Test(str string, callback Callback) { //pointer 转 string straddress := &callback strPiniter := fmt.Sprintf("%d", unsafe.Pointer(straddress)) fmt.Println("connection is", strPiniter) //string 转 pointer intPointer, _ := strconv.ParseInt(strPiniter, 10, 0) var pointer *Callback pointer = *(**Callback)(unsafe.Pointer(&intPointer)) (Callback)(*pointer)(str) Fun = (Callback)(*pointer) } package main import "hello/test_cycle_b" import _ "hello/test_cycle_a" func main(){ test_cycle_b.Fun("lizhaolong") } ouput: connection is 824634925080 hello : hello world hello : lizhaolong倘若我们在package test_cycle_b把Test函数换成如下函数:
func Test(str string, callback Callback) { Fun = callback return }继续调用上面的main函数,我们发现仍旧是可以成功运行的,其实此时就和第一种解决方案一样了。
其实在[1]中还提到了使用HTTP请求解决,这个我在网上并没有找到相关内容。但是就目前来看,第一种方案已经很好的解决了我们的问题,如果有其他更好的方案可以解决这个问题大家可以留言讨论
参考:
博文《golang解决import cycle not allowed的一种思路》博文《bugfan/mytools》