我有一个包,其中有两个接口
package main
type A interface {
Close()
}
type B interface {
Connect() (A, error)
}
我还有两个实现这些接口的结构
type C struct {
}
func (c *C) Close() {
}
type D struct {
}
func (d *D) Connect() (*C, error) {
c := new(C)
return c, nil
}
接下来我有一个函数,它需要一个实现接口 B 的对象作为参数
func test(b B) {
}
最后,在 main() 函数中我创建了 D 结构对象并想调用 test() 函数
func main() {
d := new(D)
test(d)
}
如果我尝试构建那个包,我会出错。
不能在要测试的参数中使用 d(类型 *D)作为类型 B: *D 没有实现 B(Connect 方法的类型错误) 有 Connect() (*C, 错误) 想要连接()(A,错误)
这是我的代码的简单示例,我使用外部包并希望模拟结构进行测试。使用接口而不是类型有什么解决方案吗?
对于接口的实现,有一个需要关注的是:
Go 类型通过实现接口的方法来满足接口 接口,仅此而已。此属性允许定义接口 无需修改现有代码即可使用。它使一种 促进关注点分离和改进的结构类型 代码重用,并且更容易建立在出现的模式之上 代码开发。
你得到的错误是因为你用作测试函数参数的结构
D
没有实现接口。这背后的原因是您与接收器 Connect
一起使用的功能 D
是不同的。因为它有不同的返回类型:
func (d *D) Connect() (*C, error) { // the struct D does not implement the interface B because of wrong function definition to interface B function
c := new(C)
return c, nil
}
而如果你想实现接口
B
函数定义及其返回类型应该匹配接口中的函数B
这是
type B interface {
Connect() (A, error)
}
所以如果你想实现接口,你使用的Connect方法应该匹配接口B的Connect方法
package main
type A interface {
Close()
}
type B interface {
Connect() (A, error)
}
type C struct {
}
func (c *C) Close() {
}
type D struct {
}
func (d *D) Connect() (A, error) {
c := new(C)
return c, nil
}
func test(b B) {}
func main() {
d := new(D)
test(d)
}
考虑这个简单的接口来表示一个可以将自身与另一个值进行比较的对象:
type Equaler interface {
Equal(Equaler) bool
}
还有这种类型,T:
type T int
func (t T) Equal(u T) bool { return t == u } // does not satisfy Equaler
T.Equal 的参数类型是 T,不是字面上要求的类型 Equaler。
在Go中,类型系统不提倡Equal的论证;这是程序员的责任,如类型 T2 所示,它确实实现了 Equaler:
type T2 int
func (t T2) Equal(u Equaler) bool { return t == u.(T2) } // satisfies Equaler
您的
Connect
方法的返回类型应该是 A
而不是 *C
.
您定义
Connect
方法的方式是它应该返回一个接口,而不是特定类型。您仍然可以返回*C
,因为它实现了A
接口。
package main
type A interface {
Close()
}
type B interface {
Connect() (A, error)
}
type C struct {
}
func (c *C) Close() {
}
type D struct {
}
func (d *D) Connect() (A, error) {
c := new(C)
println("successfully created new C:", c)
return c, nil
}
func test(b B) {
b.Connect()
}
func main() {
d := new(D)
test(d)
}
输出
成功创建新的C:0xe28f0
自己试试在这里