Es wird ein bisschen mehr offensichtlich, wenn Sie Ihr Beispiel über diesen einen einfachen Fall hinaus erweitern (kein Wortspiel beabsichtigt).
Mehrfachvererbung:
class C[A] extends X with Y with Z
Mixins:
val x = new X with Y
Parametrierung:
class X[A <: B] extends Y[A]
Multiple (bezogen) Typ params:
class X[A >: B, B](x: A, xs: Seq[B])
Grenzen
Kontext:
class X[A : Manifest]
Ansicht Grenzen:
class X[A <% Ordered[A]]
Generisches Methoden:
class Foo[B] {
def bar[A <: B](x: A) = ...
}
Wie Sie sehen können, die Beziehungen sehen, die in einem Typ-Parameter angegeben werden können, sind viel reicher als die einfache lineare Hierarchie, die beim Deklarieren einer Klasse verfügbar ist, besonders wenn Sie al sind niedrig für Grenzen.
Es ist auch erwähnenswert, dass generische Typparameter für die Klassen oder Methoden werden sehr häufig geschlossen werden, so dass Sie schreiben:
val myList = List(1, 2, 3)
statt
val myList = List[Int](1, 2, 3)
So ist die Art und Weise, in der die Notationen verwendet werden, ist sehr unterschiedlich.
Update
Ein besonderes Beispiel ist Frühling gerade in dem Sinne, die Verwendung beiden Schreibweisen gleichzeitig demonstrieren und zeigt, wie sie müssen unterscheidbar bleiben:
def someMethod[T <: Foo with Bar](x: T) = ...
Dies erfordert, dass der Typ-param T
ein Subtyp etwas Mischen in beiden Foo
und Bar
sein.
Das gleiche gilt für Strukturtypen:
type Closable = { def close: Unit } //alias for a structural type
def someMethod[T <: Closable](x: T) = ...
++ 1 für die Diskussion über den Unterschied zwischen Klassen und Typen –
in Bezug auf Klassen und Typen als verschiedene Dinge macht es Sinn, verschiedene Notationen zu verwenden. Danke für die Erklärung. – sschaef