脚本之家

电脑版
提示:原网页已由神马搜索转码, 内容由www.jb51.net提供.
您的位置:首页脚本专栏Golang→ golang包循环引用

golang包循环引用的几种解决方案总结

  更新时间:2022年09月19日 09:03:52  作者:云满笔记 
golang有包循环引用问题,用过的应该都知道,下面这篇文章主要给大家介绍了关于golang包循环引用的几种解决方案,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

1. golang 包循环引用的几种解决方案

1.1. 前言

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

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

package_i

package package_i

type PackageAInterface interface {
PrintA()
}

type PackageBInterface interface {
PrintB()
}

package_a

package package_a

import (
"cycle/package_i"
"fmt"
)

type PackageA struct {
B package_i.PackageBInterface
}

func (a PackageA) PrintA() {
fmt.Println("I'm a!")
}

func (a PackageA) PrintAll() {
a.PrintA()
a.B.PrintB()
}

package_b

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

main

package main

import (
"cycle/package_a"
"cycle/package_b"
)

func main() {
a := new(package_a.PackageA)
b := new(package_b.PackageB)
a.B = b
b.A = a
a.PrintAll()
b.PrintAll()
}

1.3. 新建公共组合包(子包), 在组合包中组合调用

package_c

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

main

package main

import (
"cycle/package_a"
"cycle/package_b"
"cycle/package_c"
)

func main() {
a := new(package_a.PackageA)
b := new(package_b.PackageB)
c := new(package_c.CombileAB)
c.A = a
c.B = b
c.PrintAll()
}

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

callback_mgr

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

package_a

package package_a

import (
"cycle/callback_mgr"
"fmt"
)

func init() {
callback_mgr.RegisterCallBack("getA", new(PackageA).GetA)
}

type PackageA struct {
}

func (a PackageA) GetA() string {
return "I'm a!"
}

func (a PackageA) PrintAll() {
fmt.Println(a.GetA())
fmt.Println(callback_mgr.CallBackFunc("getB")[0].(string))
}

package_b

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

main

package main

import (
"cycle/package_a"
"cycle/package_b"
)

func main() {
a := new(package_a.PackageA)
b := new(package_b.PackageB)
a.PrintAll()
b.PrintAll()
}

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

eventBus

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

package_a

package package_a

import (
"cycle/eventBus"
"fmt"
)

func init() {
eventBus.Subscribe("PrintA", new(PackageA).PrintA)
}

type PackageA struct {
}

func (a PackageA) PrintA() {
fmt.Println("I'm a!")
}

func (a PackageA) PrintAll() {
a.PrintA()
eventBus.Publish("PrintB")
}

package_b

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

总结

到此这篇关于golang包循环引用的几种解决方案的文章就介绍到这了,更多相关golang包循环引用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

    • Go语言是采用UTF8编码的,理论上使用任何文本编辑器都能做Go语言开发,下面这篇文章主要给大家介绍了关于使用VS code快速搭建一个Golang项目的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
      2023-04-04
    • 这篇文章主要为大家介绍了go语言beego框架jwt身份认证实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
      2022-04-04
    • 语法糖,也称糖语法,是由英国计算机科学家彼得·兰丁提出的,用于表示编程语言中的某种类型的语法,这些语法不会影响功能,但使用起来却很方便,本文就来看看Golang中常用的语法糖有哪些吧
      2023-05-05
    • golang协程机制很方便的解决了并发编程的问题,但是协程并不是没有开销的,所以也需要适当限制一下数量。这篇文章主要介绍了golang 40行代码实现通用协程池,需要的朋友可以参考下
      2018-08-08
    • 这篇文章主要介绍了Golang 实现插入排序的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
      2020-02-02
    • 本文主要为大家详细介绍了Golang中slice的底层实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
      2023-02-02
    • 在写 Go 的过程中经常对比这Java和GO语言的特性,踩了不少坑,也发现了不少有意思的地方,今天就来聊聊 Go 自带的 HttpClient 的超时机制
      2022-11-11
    • 这篇文章主要介绍了Go 将在下个版本支持新型排序算法:pdqsort,而就Go支持pdqsort算法,在HN上引起了不少的讨论,有人表示,我们研究排序算法这么久了,很惊讶我们还能想出能产生实际改进的优化方案。对此,你怎么看,快快上手体验一下吧
      2022-04-04
    • 本篇文章剖析下 Go 定时器的相关内容。定时器不管是业务开发,还是基础架构开发,都是绕不过去的存在,由此可见定时器的重要程度,感兴趣的可以了解一下
      2021-06-06
    • 比特币钱包实际上是一个密钥对,当你安装 一个钱包应用,或者是使用一个比特币客户端来生成一个新地址是,他就会为你生成一个密钥对,今天通过本文给大家分享go语言遍历钱包的相关知识,一起看看吧
      2021-05-05

    最新评论