Use Listener mechanism to solve Golang package circular reference

introduction

This problem appears in the problem encountered in writing projects, that is, the circular reference of the package. The introduction of the Listener mechanism can solve this problem. In fact, this solution can also be extended to other languages.

solve

In fact, the description of the problem is very easy, that is, there are references between the two packages. Of course, the best solution is to take this problem into account when designing, so as to avoid this problem at the design stage, but not everyone can The design stage looks so deep, so when this problem occurs, we need a mechanism to solve this problem, in fact, it is a special callback mechanism.

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)
}

We can clearly see that the A package contains the ServerConfig in the B package, and the B package will be used again LoadServerConfig. At this time, a circular reference will appear. The solution is to introduce one ServerListeners, initwhich is regarded LoadServerConfigas a callback call in the function of the A package. RegisterRestServerListenerPut the ServerListeners into the ServerListeners. At this time, there is no need to directly call the B package in the B package. The callback in the LoadServerConfigdirect call ServerListenersis OK, but we also need to introduce the A package where the B package needs to be called, and importadd it at the end _, which means Execute the initfunctions in the package so that the functions of package A can be linked to package B.

In fact, there is another method, which is the method in [1], but I personally think that they are almost the same. I didn’t really understand the meaning of the pointer turning around. I thought that I wrote a simple test code to see that the turning does not turn. All can run through.

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

If we are package test_cycle_breplacing the Test function with the following function:

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

Continuing to call the above mainfunction, we found that it can still run successfully, in fact, it is the same as the first solution at this time.

In fact, it was mentioned in [1] to use HTTP request to solve it. I didn't find relevant content on the Internet. But for now, the first solution has solved our problem very well. If there are other better solutions that can solve this problem, you can leave a message to discuss

reference:

  1. Blog post " Golang's idea of ​​solving import cycle not allowed "
  2. Hirofumi 《bugfan / mytools

Guess you like

Origin blog.csdn.net/weixin_43705457/article/details/109194901