0
点赞
收藏
分享

微信扫一扫

使用Listener机制解决Golang包环状引用


引言

这个问题出现在写项目中遇到的问题,即包的环状引用,引入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 :

倘若我们在​​package test_cycle_b​​把Test函数换成如下函数:

func Test(str string, callback Callback)  {
Fun = callback
return
}

继续调用上面的​​main​​函数,我们发现仍旧是可以成功运行的,其实此时就和第一种解决方案一样了。

其实在[1]中还提到了使用HTTP请求解决,这个我在网上并没有找到相关内容。但是就目前来看,第一种方案已经很好的解决了我们的问题,如果有其他更好的方案可以解决这个问题大家可以留言讨论

参考:

  1. 博文《​​golang解决import cycle not allowed的一种思路​​》
  2. 博文《​​bugfan/mytools​​》


举报

相关推荐

0 条评论