【发布时间】:2021-06-08 17:16:45
【问题描述】:
在 Go 中,有没有办法使用方法来实现接口,其中实现中对应方法的返回类型“比”预期的返回类型“宽”?
这很难解释,所以这里举个例子。在 Go Playground 中运行以下示例代码时出现此错误:
./prog.go:36:14: cannot use BirdImpl{} (type BirdImpl) as type Animal in argument to foo:
BirdImpl does not implement Animal (wrong type for Move method)
have Move() BirdMoveResult
want Move() AnimalMoveResult
(其中BirdMoveResult“比”AnimalMoveResult“宽”,因为BirdMoveResult 的任何实现也是AnimalMoveResult 的实现)
package main
type (
Animal interface {
Move() AnimalMoveResult
}
Bird interface {
Move() BirdMoveResult
}
AnimalMoveResult interface {
GetDistance() int
}
BirdMoveResult interface {
GetDistance() int
GetHeight() int
}
BirdImpl struct{}
BirdMoveResultImpl struct{}
)
// Some implementation of BirdImpl.Move
// Some implementation of BirdMoveResultImpl.GetDistance
// Some implementation of BirdMoveResultImpl.GetHeight
func foo(animal Animal) int {
return animal.Move().GetDistance()
}
func main() {
foo(BirdImpl{}) // This fails because BirdImpl doesn't implement Animal. My question is why not?
}
我知道 Move() 方法签名不完全匹配,因为返回类型不同,因此 Go 不会将 BirdImpl 视为 Animal 的实现。然而,如果 Go 比较返回类型,BirdMoveResult 的任何实现也将实现AnimalMoveResult。那么,Move() BirdMoveResult 不应该是Move() AnimalMoveResult 的可接受实现吗(如果不是,为什么不呢)?
编辑:在实际场景中,Animal、AnimalMoveResult 和foo 是外部包的一部分。在我自己的代码中,我希望能够使用我自己的接口方法扩展AnimalMoveResult(就像在示例中使用BirdMoveResult 所做的那样),同时仍然能够通过使用扩展接口来使用foo。
【问题讨论】:
-
虽然我很欣赏传达问题的努力,但这种类型系统看起来真的很复杂。基本上,您有多个冗余层将您从唯一的实质内容中撬开:
GetDistance()(和未使用的GetHeight())。 -
为了让一个类型满足接口,它必须实现接口中定义的所有方法完全按照接口中定义的方式。
-
@HymnsForDisco 这似乎是多余的,因为这是我试图沟通的问题的(过度)简化示例
-
@Adrian 这就是我的想法(以及答案有助于确认的内容),我想我的问题更多是关于为什么 Go 不支持这种类型的接口匹配/尝试有什么限制支持一下
-
Go 的设计目标之一是简化类型系统。将接口视为使不同部分更顺畅地协同工作的油脂。它应该只应用在正确的地方,否则事情会变得非常混乱。
标签: go