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
, init
which is regarded LoadServerConfig
as a callback call in the function of the A package. RegisterRestServerListener
Put 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 LoadServerConfig
direct call ServerListeners
is OK, but we also need to introduce the A package where the B package needs to be called, and import
add it at the end _
, which means Execute the init
functions 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_b
replacing the Test function with the following function:
func Test(str string, callback Callback) {
Fun = callback
return
}
Continuing to call the above main
function, 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:
- Blog post " Golang's idea of solving import cycle not allowed "
- Hirofumi 《bugfan / mytools》