英文:
Implicit interface conversion in golang
问题
这是我想要演示的想法的一个示例。
package main
import "fmt"
// 接口声明
type A interface {
AAA() string
}
type B interface{
Get() A
}
// 实现
type CA struct {}
// 实现 A.AAA 方法
func (ca *CA) AAA() string {
return "it's CA"
}
type C struct {}
// 实现 B.Get 方法,返回一个结构体而不是接口
func (c *C) Get() *CA {
return &CA{}
}
func main() {
var c interface{} = &C{}
d := c.(B)
fmt.Println(d.Get().AAA())
fmt.Println("Hello, playground")
}
在这个例子中:
- 接口
B
有一个方法Get
,返回一个接口A
- 结构体
C
有一个成员函数Get
,返回一个指向结构体CA
的指针,该结构体实现了接口A
结果是,Go 无法从结构体 C
推断出接口 B
,即使它们的 Get
方法只是返回类型不同,但是可以转换。
我提出这个问题的原因是当接口 A、B和结构体 C、CA位于不同的包中时,我只能:
- 将
C
的Get
方法改为 func Get() A,这样会在包之间引入一些依赖关系。 - 将接口
B
和结构体C
的Get
方法都改为 func Get() interface{}
我想避免包之间的依赖关系,并尽量不依赖于 interface{},有人能给我一些提示吗?在 Go 中有什么最佳实践?
英文:
Here is an example of the idea I want to demonstrate.
package main
import "fmt"
// interface declaration
//
type A interface {
AAA() string
}
type B interface{
Get() A
}
// implementation
//
type CA struct {}
// implementation of A.AAA
func (ca *CA) AAA() string {
return "it's CA"
}
type C struct {}
// implementation of B.Get, except for returning a 'struct' instead of an 'interface'
func (c *C) Get() *CA {
return &CA{}
}
func main() {
var c interface{} = &C{}
d := c.(B)
fmt.Println(d.Get().AAA())
fmt.Println("Hello, playground")
}
In this example
- interface
B
has a methodGet
to return an interfaceA
- struct
C
has a member functionGet
to return a pointer to structCA
, which implements interfaceA
The result is Go can't deduce interface B
from struct C
, even their Get
method is only different in returning type, which is convertible.
The reason I raise this question is when interface A, B and struct C, CA are in different packages, I can only:
- refine the Get method of
C
to func Get() A, which introduce some dependency between packages. - refine both
Get
method of interfaceB
and structC
to func Get() interface{}
I want to avoid dependency between packages and try not to rely on interface{}, can anyone give me some hint? What's the best practice in Go?
答案1
得分: 3
你当前的*C
类型没有实现接口B
,因此你不能将*C
类型的值赋给B
类型的变量,也不能从持有*C
类型值的对象中进行“类型断言”以获取B
类型的值。
以下是你可以做的。由于你已经在使用结构体字面量(&C{}
),你可以声明c
为*C
类型,然后调用它的Get()
方法,并将C.Get()
的返回值转换为A
类型(因为返回值实现了A
接口):
var c *C = &C{}
var a A = c.Get() // 这是可以的,隐式接口值创建(类型为A)
fmt.Println(a.AAA())
// 或者不使用中间变量"a",直接调用:
fmt.Println(c.Get().AAA())
输出结果:
it's CA
it's CA
或者进行重构:
问题在于你想要实现一个接口B
,该接口具有返回另一个接口A
的方法。要实现这个B
接口,你必须依赖定义A
的包,无法避免这一点。并且你必须声明C.Get()
返回A
(而不是具体的结构体类型)。
你可以将A
移动到第三个包中,然后定义C
的包只需要依赖这个第三个包,而不依赖定义B
的包(但仍然会隐式实现接口类型B
)。
英文:
Your current *C
type does not implement the interface B
, therefore you can't assign a value of *C
to a variable of type B
nor can't you "type assert" a value of B
from something holding a value of type *C
.
Here's what you can do. Since you're already using a struct literal (&C{}
), you may declare c
to be of type *C
of which you can call its Get()
method, and you can convert the return value of C.Get()
to A
(because the return value does implement A
):
var c *C = &C{}
var a A = c.Get() // This is ok, implicit interface value creation (of type A)
fmt.Println(a.AAA())
// Or without the intermediate "a", you can simply call:
fmt.Println(c.Get().AAA())
Output:
it's CA
it's CA
Or refactor:
The problem is that you have an interface (B
) which you want to implement, which has a method which returns another interface (A
). To implement this B
interface, you have to have dependency to the package that defines A
, you can't avoid this. And you have to declare C.Get()
to return A
(instead of a concrete struct type).
You may move A
to a 3rd package and then the package that defines C
will only have to depend on this 3rd package, but will not depend on the package that defines B
(but still will implicitly implement the interface type B
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论