Go 使用更广泛的方法签名实现接口
在Go中,是否有一种方法可以使用方法实现接口,其中实现中相应方法的返回类型比预期的返回类型“宽” 这很难解释,所以这里有一个例子。我在Go Playerly中运行以下示例代码时遇到此错误:Go 使用更广泛的方法签名实现接口,go,Go,在Go中,是否有一种方法可以使用方法实现接口,其中实现中相应方法的返回类型比预期的返回类型“宽” 这很难解释,所以这里有一个例子。我在Go Playerly中运行以下示例代码时遇到此错误: ./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 metho
./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
的实现)
<>我知道,由于不同的返回类型,“代码> MOVER())/代码>方法签名完全不匹配,因此GO不考虑<代码> ByDimpLP/COD>作为<代码>动物< /代码>的实现。但是,如果Go比较返回类型,则任何BirdMoveResult
的实现也将实现AnimalMoveResult
。那么,Move()BirdMoveResult
不应该是Move()AnimalMoveResult
的可接受实现吗(如果不是,为什么不是)
编辑:在实际场景中,
Animal
、animaloveresult
和foo
是外部包的一部分。在我自己的代码中,我希望能够使用自己的接口方法扩展AnimalMoveResult
(正如在BirdMoveResult
示例中所做的),同时仍然能够使用扩展接口使用foo
。不可以。方法签名必须完全匹配。Go没有协变或逆变的概念。这些问题通常是由以下原因造成的:
- 过早接口
- 假接口,或“气泡包装”(见我的咆哮)
- 并行接口
类型移动器接口{
Move()MoveResult
}
对于MoveResult,您可以这样做(如果愿意,可以用int交换float):
类型MoveResult结构{
距离,高度
}
考虑到以下假设,此类型可能作为结构正常工作:
- 移动结果只是数据点(它们不需要是动态的;您可以设置值并保留它们)
- “额外”数据(如高度)在未指定时正确使用零值
类型Bird结构{
//一些内部数据
}
func(b*Bird)Move()MoveResult{
//一些运动计算
返回MoveResult{距离:多远,高度:多高}
}
现在实现foo:
func foo(移动器)浮动64{
返回m.Move()距离
}
现在主要使用它:
func main(){
foo(&Bird{})
}
现在我们可以在程序中添加其他类型的Mover
s,并将它们与foo
一起使用,而不会出现问题
处理您的评论,其中
Animal
、AnimalMoveResult
和foo
都是外部的,您不能修改它们:
我的理解是如何提出问题的:有一个函数foo
,设计用于接受一个名为Animal
的接口,其特点是它如何返回专有类型。您希望将您的类型Bird
用作动物
,但您无法将您想要的所有行为都纳入该专有返回类型
那么如何解决这个问题呢
实现您自己的、更广泛的返回类型
类型birdOversult结构{
//一些内部数据
}
func(r birdMoveResult)GetDistance()int{
//保持距离
}
func(r birdMoveResult)GetHeight()int{
//获得高度
}
现在,实现Bird类型
类型Bird结构{
//一些内部数据
}
func(b*Bird)Move()动物结果{
var结果BIRDMOVERSULT
//计算移动结果
回鸟结果
}
请注意,Move
返回AnimalMoveResult
类型,因此现在Bird
将满足Animal
接口。我们之所以能够这样做,是因为birdMoveResult
满足AnimalMoveresult
类型,所以在这里返回它是合法的
剩下的问题是Bird
的Move
方法缩小了广泛的界面,实际上我们已经失去了您添加的新功能。为了在仍然满足Animal
界面的情况下将其取回,我们根本不能更改Move
方法签名。这里有两种可能的解决方法
var b Bird
// ...
高度:=b.Move()(birdMoveResult).GetHeight()
Bird
添加一个新方法,该方法返回更宽的类型,使现有的Move
具有相同的签名func(b*Bird)MoveFull()birdMoveResult{
var结果BIRDMOVERSULT
//计算移动结果
回鸟结果
}
func(b*Bird)Move()动物结果{
返回b.MoveFull()
}
height:=b.MoveFull().GetHeight()
这两种方法中的任何一种都会起作用
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?
}