1. golang 包循环引用的几种解决方案
1.1. 前言
golang 为了加速编译, 不允许包循环引用。通常来说, 只要你的包规划得好, 严格规范单向调用链 (如控制层 -> 业务层 ->数据层), 一般不会出现包循环引用问题。当然现实业务往往不会这么理想, 同层级之间的不同包经常需要互相引用, 下面我就分享几种解决包循环引用的方案。
1.2. 新建公共接口包(父包), 将需要循环调用的函数或方法抽象为接口
package_i
1
2
3
4
5
6
7
8
9
|
package package_i type PackageAInterface interface { PrintA() } type PackageBInterface interface { PrintB() } |
package_a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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包循环引用内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://blog.csdn.net/wan212000/article/details/123261256