英文:
How to implement two different interfaces with the same method signature
问题
在这种情况下,你可以使用类型转换来解决问题。由于A.Doer
和B.Doer
是两个不同的接口,你需要将C
类型转换为这两个接口类型的实现。
在main
包中,你可以创建两个新的类型,分别实现A.Doer
和B.Doer
接口。然后,在main
函数中,你可以将C
类型的实例转换为这两个接口类型,并将它们传递给A.FuncA
和B.FuncB
函数。
以下是修改后的代码示例:
package main
import (
"path/to/A"
"path/to/B"
)
type C int
// 实现 A.Doer 接口
func (c C) Do() string {
return "C now implements A"
}
// 实现 B.Doer 接口
func (c C) DoB() string {
return "C now implements B"
}
func main() {
c := C(0)
// 将 C 类型转换为 A.Doer 接口类型
aDoer := A.Doer(c)
A.FuncA(aDoer)
// 将 C 类型转换为 B.Doer 接口类型
bDoer := B.Doer(c)
B.FuncB(bDoer)
}
通过这种方式,你可以在不同的包中使用相同的类型实现不同的接口,并且不会出现冲突或错误。
英文:
Suppose that I have to implement two different interfaces declared in two different packages (in two different separated projects).
I have in the package A
package A
type interface Doer {
Do() string
}
func FuncA(Doer doer) {
// Do some logic here using doer.Do() result
// The Doer interface that doer should implement,
// is the A.Doer
}
And in package B
package B
type interface Doer {
Do() string
}
function FuncB(Doer doer) {
// some logic using doer.Do() result
// The Doer interface that doer should implement,
// is the B.Doer
}
In my main
package
package main
import (
"path/to/A"
"path/to/B"
)
type C int
// this method implement both A.Doer and B.Doer but
// the implementation of Do here is the one required by A !
func (c C) Do() string {
return "C now Imppement both A and B"
}
func main() {
c := C(0)
A.FuncA(c)
B.FuncB(c) // the logic implemented by C.Do method will causes a bug here !
}
How to deal with this situation ?
答案1
得分: 9
根据常见问题解答中提到的:
通过其他语言的经验,我们发现,具有相同名称但不同签名的多种方法有时很有用,但在实践中可能会令人困惑和脆弱。
在Go的类型系统中,只通过名称匹配并要求类型一致是一个重要的简化决策。
在你的情况下,你可以同时满足这两个接口。
你可以通过以下方式测试一个对象(接口类型的对象)是否满足另一个接口类型 A.Doer
:
if _, ok := obj.(A.Doer); ok {
}
问题补充:
但是,用于满足
A
的Do
方法中的逻辑与B
中的逻辑完全不同。
那么你需要在你的对象周围实现一个包装器:
DoerA
,它将你的对象C
作为字段,并以满足A.Do()
的方式实现A.Do()
DoerB
,它将相同的对象C
作为字段,并以满足B.Do()
的方式实现B.Do()
这样,你就知道要将哪个 Doer
传递给期望 A.Doer
或 B.Doer
的函数。
你不需要在原始对象 C
上实现一个 Do()
方法,因为它无法处理 A.Do()
和 B.Do()
的不同逻辑。
英文:
As the FAQ mentions
> Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice.
Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.
In your case, you would satisfy both interfaces.
You can you the can test whether an object (of an interface type) satisfies another interface type A.Doer
, by doing:
if _, ok := obj.(A.Doer); ok {
}
The OP adds:
> But the logic implemented in the Do
method to satisfy A
is completely different from the one in B
.
Then you need to implement a wrapper around you object:
- a
DoerA
, which has your objectC
as a field, and implementA.Do()
in a manner that satisfy howA.Do()
is supposed to work - a
DoerB
, which has your same objectC
as a field, and implementB.Do()
in a manner that satisfy howB.Do()
is supposed to work
That way, you will know which Doer to pass to a function expecting an A.Doer
or a B.Doer
.
You won't have to implement a Do()
method on your original object C
, which would be unable to cope with the different logic of A.Do()
and B.Do()
.
答案2
得分: 4
根据定义,你同时满足以下两个条件:
- 通过实现接口的方法,一个Go类型可以满足一个接口的要求,没有其他要求。这个特性使得可以定义和使用接口而无需修改现有的代码。它实现了一种结构化的类型,促进了关注点的分离和代码的重用,使得在代码发展过程中更容易构建出现的模式。接口的语义是Go语言具有灵活、轻量级特性的主要原因之一。
因此,在这个基础上,你可以选择:
a) 在接口方法中添加注释,定义对逻辑的期望(参考io.Reader接口或一个很好的例子)。
b) 在接口上添加一个额外的方法,命名为ImplementsDoerA和ImplementsDoerB(FAQ中也提到了这一点)。
英文:
By definition, you are satisfying both:
> A Go type satisfies an interface by implementing the methods of that interface, nothing more. This property allows interfaces to be defined and used without having to modify existing code. It enables a kind of structural typing that promotes separation of concerns and improves code re-use, and makes it easier to build on patterns that emerge as the code develops. The semantics of interfaces is one of the main reasons for Go's nimble, lightweight feel.
So, with that in mind, you can either:
a) Add comments to the the interface methods defining your expectations on the logic (see the io.Reader interface or a good example)
b) Add an extra method called ImplementsDoerA and ImplementsDoerB on the interfaces (also mentioned in the FAQ).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论