6

私たちが持っていると考えてください:

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

これら2つの関数宣言の違いは何ですか:

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 を返すため、代わりは:

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

Rocket が渡された場合、Rocket を返します。

于 2012-04-23T16:57:41.137 に答える
4

@stewの回答に加えて、型クラスを使用するときに上限が役立つ場合があります。たとえば、2 つの飛行オブジェクトと、他のオブジェクトとの衝突を管理する方法を定義するコライダー オブジェクトを受け取るメソッドが必要だとします。もちろん、小惑星と小惑星の衝突は、宇宙船と小惑星の衝突と同じではありません (古典的な教科書の例)。

次のようなメソッドを書くことができます。

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)

衝突を管理するには、Obect 指向の機能に依存する必要があります。これは、書き込みと保守が非常に困難です (二重ディスパッチの問題)。

于 2012-04-23T17:40:34.397 に答える