2010-11-26 2 views
5

Почему существуют разные обозначения для наследования? В generics я должен использовать <: -оператор - в обычном наследовании класса я должен использовать ключевое слово extends.Различные обозначения для наследования наследования

Например, я должен написать это:

class X[A <: B] extends Y 

Но почему бы не писать что-то вроде этого:

class X[A <: B] <: Y 

или

class X[A extends B] extends Y // like Java 

у меня нет проблем с текущей записи , но я хочу знать, есть ли причина для обозначения иерархии типов дженериков по-другому.

ответ

12

Ну, нет ничего остановки Scala от этого, но, как на самом деле, они не выражают то же самое на всех , И, на самом деле, вы можете видеть, что на Java, где вы можете написать X super Y, но вы не можете сказать class X super Y.

Ключевое слово extends выражает связь между классов, одного из наследования. С другой стороны, <: и >: выражают связь между типами, одной из границ. Когда я говорю X <: Y, то он действителен и для X, и для Y будет String, например, в то время как String extends String будет бессмысленным. Это также случай, когда List[String] <: List[AnyRef], опять же, List[String] extends List[AnyRef] не имеет смысла. И, просто чтобы сказать, это не true, что Set[String] <: Set[AnyRef]. Во всех этих примерах я просто сказал, что мы говорим о том же класс, но нет, обязательно, примерно то же самое тип.

И, конечно, существуют и другие отношения между типами, такие как границы обзора (<%) и границы контекста (:).

Таким образом, только потому, что extends подразумевает <:, это не означает, что <: подразумевает extends, который сам по себе, является достаточной причиной, чтобы избежать использования того же ключевого слова. Добавьте к этому другие отношения между типами, и у вас есть довольно закрытая сделка.

+1

++ 1 для разговора между классами и типами – 2010-11-27 12:33:29

7

Это становится немного более очевидным, когда вы расширяете (не каламбур) свой пример за пределы одного простого случая.

Множественное наследование:

class C[A] extends X with Y with Z 

Примеси:

val x = new X with Y 

Параметрирование:

class X[A <: B] extends Y[A] 

Множественные (связанные) PARAMS Тип:

class X[A >: B, B](x: A, xs: Seq[B]) 

Контекст оценки:

class X[A : Manifest] 

Посмотреть Bounds:

class X[A <% Ordered[A]] 

Generic Методы:

class Foo[B] { 
    def bar[A <: B](x: A) = ... 
} 

Как вы можете видеть, отношения, которые могут быть указаны в качестве параметра типа намного богаче простой линейной иерархии, доступной при объявлении класса, особенно когда вы низкий для границ.

Стоит также отметить, что параметры универсального типа для классов или методов очень часто можно сделать вывод, что позволяет написать:

val myList = List(1, 2, 3) 

вместо

val myList = List[Int](1, 2, 3) 

Таким образом, способ, в котором нотации используются очень разные.

обновление

Один конкретный пример только на ум, демонстрирующий использование обеих нотаций одновременно и показывая, как они должны оставаться различны:

def someMethod[T <: Foo with Bar](x: T) = ... 

Это требует, типа-парам T быть подтипом что-то смешивание в обоих Foo и Bar.

То же самое относится и со структурными типами:

type Closable = { def close: Unit } //alias for a structural type 
def someMethod[T <: Closable](x: T) = ... 
Смежные вопросы