golang包循環(huán)引用的幾種解決方案總結(jié)
1. golang 包循環(huán)引用的幾種解決方案
1.1. 前言
golang 為了加速編譯, 不允許包循環(huán)引用。通常來說, 只要你的包規(guī)劃得好, 嚴(yán)格規(guī)范單向調(diào)用鏈 (如控制層 -> 業(yè)務(wù)層 ->數(shù)據(jù)層), 一般不會出現(xiàn)包循環(huán)引用問題。當(dāng)然現(xiàn)實(shí)業(yè)務(wù)往往不會這么理想, 同層級之間的不同包經(jīng)常需要互相引用, 下面我就分享幾種解決包循環(huán)引用的方案。
1.2. 新建公共接口包(父包), 將需要循環(huán)調(diào)用的函數(shù)或方法抽象為接口
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. 新建公共組合包(子包), 在組合包中組合調(diào)用
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. 全局存儲需要相互依賴的函數(shù), 通過關(guān)鍵字進(jìn)行調(diào)用
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. 不需要回調(diào)結(jié)果的可以通過事件總線 (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")
}
總結(jié)
到此這篇關(guān)于golang包循環(huán)引用的幾種解決方案的文章就介紹到這了,更多相關(guān)golang包循環(huán)引用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用gRPC實(shí)現(xiàn)獲取數(shù)據(jù)庫版本
這篇文章主要為大家詳細(xì)介紹了如何使用gRPC實(shí)現(xiàn)獲取數(shù)據(jù)庫版本,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
golang 如何實(shí)現(xiàn)HTTP代理和反向代理
這篇文章主要介紹了golang 實(shí)現(xiàn)HTTP代理和反向代理的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-05-05
Golang運(yùn)行報錯找不到包:package?xxx?is?not?in?GOROOT的解決過程
這篇文章主要給大家介紹了關(guān)于Golang運(yùn)行報錯找不到包:package?xxx?is?not?in?GOROOT的解決過程,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-07-07
Go語言中TCP/IP網(wǎng)絡(luò)編程的深入講解
這篇文章主要給大家介紹了關(guān)于Go語言中TCP/IP網(wǎng)絡(luò)編程的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05
go-zero 應(yīng)對海量定時/延遲任務(wù)的技巧
這篇文章主要介紹了go-zero 如何應(yīng)對海量定時/延遲任務(wù),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
golang Iris運(yùn)行多個應(yīng)用的實(shí)現(xiàn)
本文主要介紹了golang Iris運(yùn)行多個應(yīng)用的實(shí)現(xiàn),在Iris里面,提供了一種方式可以讓我們同時運(yùn)行多個應(yīng)用,具有一定的參考價值,感興趣的可以了解一下2024-01-01

