Golang包循环依赖问题 引用 struct 相互引用

http://www.aidsay.com/golange58c85e5beaae78eafe4be9de8b596e997aee9a298/

 

Golang使用下面的语法导入一个包:

import (  
    "pkgname" 
)

pkgname其实是一个目录的相对路径,在该目录下所有Golang源文件(.go)声明的包名都必须是其所在的目录名(main包除外),即pkgname目录下每个Golang源文件(.go)都必须有:

package pkgname  

包下的源文件名除了后缀“.go”外并不重要。

下面我们看看Golang包循环依赖问题;在项目中,总有分处在不同包的两个模块需要互相调用对方成员的情况出现,例如:

a.go:

package a  
import "test/b"  
var n = 1  
func GetN() int {  
    return n 
} 
func Sum() int {  
    return n + b.GetN() 
}

b.go:

package b  
import "test/a"  
var n = 1  
func GetN() int {  
    return n 
} 
func Sum() int {  
    return n + a.GetN() 
}

test.go:

package main  
import (  
    "test/a" 
    "test/b" 
    "fmt" 
) 
func main() {  
    fmt.Println(a.Sum()) 
    fmt.Println(b.Sum()) 
}

Golang是不支持循环依赖的,所以编译会得到以下错误输出信息:

import cycle not allowed  
    package test/a 
        imports test/b 
        imports test/a

要解决这个问题可以使用接口,我们将上面的代码改写一下并且添加一个用于定义接口的包,代码如下:

er.go:

package er  
type A interface {  
    Sum()int 
    GetN()int 
} 
type B interface {  
    Sum()int 
    GetN()int 
}

a.go:

package a  
import "test/er"  
var n = 1  
func (a *A)GetN()int{  
    return n 
} 
func (a *A)Sum()int{  
    return n + a.b.GetN() 
} 
/***************************************/ 
type A struct {  
    b er.B 
} 
func NewA()*A{  
    return new(A) 
} 
func (a *A)SetB(b er.B){  
    a.b = b 
}

b.go:

package b  
import "test/er"  
var n = 1  
func (b *B)GetN()int{  
    return n 
} 
func (b *B)Sum()int{  
    return n + b.a.GetN() 
} 
/**************************************/ 
type B struct {  
    a er.A 
} 
func NewB()*B{  
    return new(B) 
}
func (b *B)SetA(a er.A){  
    b.a = a
}

test.go:

package main  
import (  
    "test/a" 
    "test/b" 
    "fmt" 
) 
func main() {  
    A := a.NewA() 
    B := b.NewB() 
    A.SetB(B) 
    B.SetA(A) 
    fmt.Println(A.Sum()) 
    fmt.Println(B.Sum()) 
}

编译运行:

2  
2  

上面的代码将模块需要向外暴露的成员用一个类封装起来(门面模式),两模块间成员的引用就变成了两个类间的互相调用,之后对这两个类分别进行抽象(接口),使两个类间的依赖变成对对方接口的依赖,从而避开了类(包)循环依赖的问题。


分享到: 微信 更多