前言
相信不少 Gopher 在寫 Golang 程序都遇到過 import cycle not allowed 問題,本人最近研讀 go-ethereum 源碼時,發現定義 interface 也能解決此問題, 還能解決連分包都不能解決的情況, 并且比分包更加簡單快捷。下面逐個講解 分包 和 定義接口 這兩種方法。
1. 應用場景
假設有如下使用場景:
A 是應用程序的框架級結構體,在 A 包含子模塊 B 和 C 的指針;
B 為了方便的使用應用的其他子模塊(比如 C )功能,所以在其結構體包含了 A 的指針;
C 要調用 A 包中的某個方法;
2. 代碼實現
其程序大致如下:
package a 代碼如下:
package a
import (
"fmt"
"github.com/ggq89/mutualdep/b"
"github.com/ggq89/mutualdep/c"
)
type A struct {
Pb *b.B
Pc *c.C
}
func New(ic int) *A {
a := A{
Pc: c.New(ic),
}
a.Pb = b.New(a)
return a
}
func Printf(v int) {
fmt.Printf("%v", v)
}
package b 代碼如下:
package b
import (
"github.com/ggq89/mutualdep/a"
)
type B struct {
Pa *a.A
}
func New(a *a.A) *B {
return B{
Pa: a,
}
}
func (b *B) DisplayC() {
b.Pa.Pc.Show()
}
package c 代碼如下:
package c
import "github.com/ggq89/mutualdep/a"
type C struct {
Vc int
}
func New(i int) *C {
return C{
Vc: i,
}
}
func (c *C) Show() {
a.Printf(c.Vc)
}
package a 依賴 package b 和 package c,同時 package b 依賴 package a 、 package c 也依賴 package a 。
main 函數代碼如下:
package main
import "github.com/ggq89/mutualdep/a"
func main() {
a := a.New(3)
a.Pb.DisplayC()
}
編譯時就會報錯如下:
import cycle not allowed
package main
imports github.com/ggq89/mutualdep/a
imports github.com/ggq89/mutualdep/b
imports github.com/ggq89/mutualdep/a
3. 定義接口
現在的問題是:
A depends on B
B depends on A
對于 A struct 和 B struct 有彼此的指針這種相互依賴問題,可以使用定義接口的方法解決,具體步驟如下:
在 package b 中 定義 a interface ; 將 b 所有使用到結構體 a 的變量和方法的地方全部轉化成 使用接口 a 的方法;在 a interface 中補充缺少的方法;
經過上面的步驟處理后, package b 代碼如下:
package b
import (
"github.com/ggq89/mutualdep/c"
)
type B struct {
Pa a
}
type a interface {
GetC() *c.C
}
func New(a a) *B {
return B{
Pa:a,
}
}
func (b *B) DisplayC() {
b.Pa.GetC().Show()
}
在 package a 中補充可能缺少的方法;
處理后, package a 中的代碼如下:
package a
import (
"fmt"
"github.com/ggq89/mutualdep/b"
"github.com/ggq89/mutualdep/c"
)
type A struct {
Pb *b.B
Pc *c.C
}
func New(ic int) *A {
a := A{
Pc:c.New(ic),
}
a.Pb = b.New(a)
return a
}
func (a *A)GetC() *c.C {
return a.Pc
}
func Printf(v int) {
fmt.Printf("%v", v)
}
4. 拆分包
再次編譯,提示如下:
import cycle not allowed
package main
imports github.com/ggq89/mutualdep/a
imports github.com/ggq89/mutualdep/b
imports github.com/ggq89/mutualdep/c
imports github.com/ggq89/mutualdep/a
現在是另一個相互依賴問題:
A depends on C
C depends on A
與前面的相互依賴不同,前面的依賴是由于 A struct 和 B struct 有彼此的指針導致的,屬于硬相互依賴;
而這里是由于 package c 中的方法調用 package a 中的方法引起的,屬于軟相互依賴;
- 這種相互依賴可以通過將方法拆分到另一個包的方式來解決;在拆分包的過程中,可能會將結構體的方法轉化為普通的函數;
引入 package f , 將方法遷移到 f 中 :
package f
import "fmt"
func Printf(v int) {
fmt.Printf("%v", v)
}
方法移動到 package f 后, package a 的代碼如下:
package a
import (
"github.com/ggq89/mutualdep/b"
"github.com/ggq89/mutualdep/c"
)
type A struct {
Pb *b.B
Pc *c.C
}
func New(ic int) *A {
a := A{
Pc: c.New(ic),
}
a.Pb = b.New(a)
return a
}
func (a *A) GetC() *c.C {
return a.Pc
}
package c隨之改成調用package f,其代碼如下:
package c
import (
"github.com/ggq89/mutualdep/a/f"
)
type C struct {
Vc int
}
func New(i int) *C {
return C{
Vc: i,
}
}
func (c *C) Show() {
f.Printf(c.Vc)
}
現在依賴關系如下:
A depends on B and C
B depends on C
C depends on F
至此,兩種包相互依賴關系都得以解決。
5. 總結
對于軟相互依賴,利用分包的方法就能解決,有些函數導致的相互依賴只能通過分包解決;分包能細化包的功能;
對于硬相互依賴只能通過定義接口的方法解決;定義接口能提高包的獨立性,同時也提高了追蹤代碼調用關系的難度;
參考文章:
- golang不允許循環import問題(“import cycle not allowed”) : https://www.jb51.net/article/145536.htm
- golang解決import cycle not allowed的一種思路 : https://www.jb51.net/article/145539.htm
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
您可能感興趣的文章:- 對Golang import 導入包語法詳解
- go各種import的使用方法講解
- golang 之import和package的使用
- MongoDB使用mongoexport和mongoimport命令,批量導出和導入JSON數據到同一張表的實例
- golang中import cycle not allowed解決的一種思路
- 詳解golang避免循環import問題(“import cycle not allowed”)
- 如何解決django配置settings時遇到Could not import settings ''conf.local''
- Golang import 導入包語法及一些特殊用法詳解