6

考虑我们有:

abstract class FlyingObject;
case class Rocket(name: String) extends FlyingObject;

这两个函数声明有什么区别:

def launch[T <: FlyingObject](fo: T)

def launch(fo: FlyingObject)

很好的例子是什么时候使用哪种类型的声明......

[更新]

另一个很好的例子和解释可以在这里找到。这是您应该使用上限而不是仅使用派生类作为参数的另一个示例。

4

2 回答 2

7

拥有比 FlyingObject 更具体的 T 可能会很有用。也许想象你有一个方法

def modifyName(fo: FlyingObject, newName: String): FlyingObject = fo.copy(name=newName)

它返回具有修改名称的 FlyingObject 副本。这使得这段代码不进行类型检查:

val newRocket: Rocket = modifyName(oldRocket, "new name")

因为 modifyName 返回的是 FlyingObject 而不是 Rocket。反而:

def modifyName[T <: FlyingObject](fo: T, newName: String): T = fo.copy(name=newName)

当 Rocket 是传入的内容时,将返回一个 Rocket。

于 2012-04-23T16:57:41.137 回答
4

除了@stew 答案,上限在使用类型类时可能很有用。例如,假设您想要一个方法,该方法采用两个飞行对象以及一个定义如何管理与其他对象的碰撞的对撞机对象。当然,小行星-小行星碰撞与宇宙飞船-小行星碰撞(经典教科书示例)不同。

您可以编写如下方法:

def collide[A <: FlyingObject, B <: FlyingObject]
  ( a: A, b: B )( implicit collider: Collider[A,B] ) = collider.apply(a,b)

然后编译器会Collider为你提供一个正确的。相反,如果您写道:

def collide( a: FlyingObject, b: FlyingObject ) = a.collide(b)

您将不得不依靠面向对象的特性来管理碰撞,这将很难编写和维护(双重调度问题)。

于 2012-04-23T17:40:34.397 回答