一、前言

golang为了加速编译,不允许包循环引用。通常来说,只要你的包规划得好,严格规范单向调用链(如控制层->业务层->数据层),一般不会出现包循环引用问题。当然现实业务往往不会这么理想,同层级之间的不同包经常需要互相引用,下面我就分享几种解决包循环引用的方案。

二、新建公共接口包(父包),将需要循环调用的函数或方法抽象为接口

  • package_i ```go package package_i

type PackageAInterface interface { PrintA() }

type PackageBInterface interface { PrintB() }

  1. - package_a
  2. ```go
  3. package package_a
  4. import (
  5. "cycle/package_i"
  6. "fmt"
  7. )
  8. type PackageA struct {
  9. B package_i.PackageBInterface
  10. }
  11. func (a PackageA) PrintA() {
  12. fmt.Println("I'm a!")
  13. }
  14. func (a PackageA) PrintAll() {
  15. a.PrintA()
  16. a.B.PrintB()
  17. }
  • package_b ```go package package_b

import ( “cycle/package_i” “fmt” )

type PackageB struct { A package_i.PackageAInterface }

func (b PackageB) PrintB() { fmt.Println(“I’m b!”) }

func (b PackageB) PrintAll() { b.PrintB() b.A.PrintA() }

  1. - main
  2. ```go
  3. package main
  4. import (
  5. "cycle/package_a"
  6. "cycle/package_b"
  7. )
  8. func main() {
  9. a := new(package_a.PackageA)
  10. b := new(package_b.PackageB)
  11. a.B = b
  12. b.A = a
  13. a.PrintAll()
  14. b.PrintAll()
  15. }

三、新建公共组合包(子包),在组合包中组合调用

  • package_c ```go package package_c

import ( “cycle/package_a” “cycle/package_b” )

type CombileAB struct { A package_a.PackageA B package_b.PackageB }

func (c CombileAB) PrintAll() { c.A.PrintA() c.B.PrintB() }

  1. - main
  2. ```go
  3. package main
  4. import (
  5. "cycle/package_a"
  6. "cycle/package_b"
  7. "cycle/package_c"
  8. )
  9. func main() {
  10. a := new(package_a.PackageA)
  11. b := new(package_b.PackageB)
  12. c := new(package_c.CombileAB)
  13. c.A = a
  14. c.B = b
  15. c.PrintAll()
  16. }

四、全局存储需要相互依赖的函数,通过关键字进行调用

  • callback_mgr ```go package callback_mgr

import ( “fmt” “reflect” )

var callBackMap map[string]interface{}

func init() { callBackMap = make(map[string]interface{}) }

func RegisterCallBack(key string, callBack interface{}) { callBackMap[key] = callBack }

func CallBackFunc(key string, args …interface{}) []interface{} { if callBack, ok := callBackMap[key]; ok { in := make([]reflect.Value, len(args)) for i, arg := range args { in[i] = reflect.ValueOf(arg) } outList := reflect.ValueOf(callBack).Call(in) result := make([]interface{}, len(outList)) for i, out := range outList { result[i] = out.Interface() } return result } else { panic(fmt.Errorf(“callBack(%s) not found”, key)) } }

  1. - package_a
  2. ```go
  3. package package_a
  4. import (
  5. "cycle/callback_mgr"
  6. "fmt"
  7. )
  8. func init() {
  9. callback_mgr.RegisterCallBack("getA", new(PackageA).GetA)
  10. }
  11. type PackageA struct {
  12. }
  13. func (a PackageA) GetA() string {
  14. return "I'm a!"
  15. }
  16. func (a PackageA) PrintAll() {
  17. fmt.Println(a.GetA())
  18. fmt.Println(callback_mgr.CallBackFunc("getB")[0].(string))
  19. }
  • package_b ```go package package_b

import ( “cycle/callback_mgr” “fmt” )

func init() { callback_mgr.RegisterCallBack(“getB”, new(PackageB).GetB) }

type PackageB struct { }

func (b PackageB) GetB() string { return “I’m b!” }

func (b PackageB) PrintAll() { fmt.Println(b.GetB()) fmt.Println(callback_mgr.CallBackFunc(“getA”)[0].(string)) }

  1. - main
  2. ```go
  3. package main
  4. import (
  5. "cycle/package_a"
  6. "cycle/package_b"
  7. )
  8. func main() {
  9. a := new(package_a.PackageA)
  10. b := new(package_b.PackageB)
  11. a.PrintAll()
  12. b.PrintAll()
  13. }

五、不需要回调结果的可以通过事件总线(eventBus)解耦

  • eventBus ```go package eventBus

import ( “github.com/asaskevich/EventBus” )

var globalEventBus EventBus.Bus

func init() { globalEventBus = EventBus.New() }

func Subscribe(topic string, fn interface{}) error { return globalEventBus.Subscribe(topic, fn) }

func SubscribeAsync(topic string, fn interface{}, transactional bool) error { return globalEventBus.SubscribeAsync(topic, fn, transactional) }

func Publish(topic string, args …interface{}) { globalEventBus.Publish(topic, args…) }

  1. - package_a
  2. ```go
  3. package package_a
  4. import (
  5. "cycle/eventBus"
  6. "fmt"
  7. )
  8. func init() {
  9. eventBus.Subscribe("PrintA", new(PackageA).PrintA)
  10. }
  11. type PackageA struct {
  12. }
  13. func (a PackageA) PrintA() {
  14. fmt.Println("I'm a!")
  15. }
  16. func (a PackageA) PrintAll() {
  17. a.PrintA()
  18. eventBus.Publish("PrintB")
  19. }
  • package_b ```go package package_b

import ( “cycle/eventBus” “fmt” )

func init() { eventBus.Subscribe(“PrintB”, new(PackageB).PrintB) }

type PackageB struct { }

func (b PackageB) PrintB() { fmt.Println(“I’m b!”) }

func (b PackageB) PrintAll() { b.PrintB() eventBus.Publish(“PrintA”) } ```