При использовании ковариационных обозначений или общих границ в Scala - PullRequest
11 голосов
/ 08 сентября 2010

В Scala дисперсию можно определить с помощью операторов дисперсии, таких как + и - для аргумента универсального типа.Например, тип List является ковариантным в стандартной библиотеке.

class List[+A]

Таким образом, функция со списком ковариант может быть определена так:

def foo[A](list : List[A])

Также можно эмулировать дисперсиюс общими границами.Таким образом, мы можем также написать это

def foo[A](list : List[_:< A])

, конечно, это не имеет смысла, потому что list уже ковариантен.Но тот же трюк можно сделать для типов, которые не являются ковариантными.(как Stack).Конечно, также могут быть созданы новые типы из стека (наследование агрегации), который является ковариантным.

Итак, мои вопросы:

  1. Когда следует использовать общие границы для дисперсии?И когда мы должны создать новый ковариантный тип?
  2. Являются ли общие границы полезными только для дисперсии, или они могут объявлять больше (языковые концепции).
  3. Если они полезны только для дисперсии, являются ли ограничения тогда только для совместимости с Java?

thx заранее:)

Ответы [ 2 ]

14 голосов
/ 08 сентября 2010

Если тип является естественно ковариантным или контравариантным, вы должны объявить это так.Ваши пользователи будут вам благодарны за это.Разница в использовании сайта действительно в основном из-за Java.Точнее, такой тип, как Array[T <: Number], рассматривается как сокращение для экзистенциального типа:

ArrayBuffer[T] forSome { type T <: Number }

Экзистенциальные типы имеют довольно громоздкий синтаксис в Scala.Это своего рода преднамеренное, потому что мы не рекомендуем вам много их использовать.Когда вам понадобится экзистенциальный тип?

  1. Для записи аналога типа Java с подстановочными знаками, например List<? extends Number>.
  2. Для записи аналога типа Java raw,такие как List.

В Java необработанные типы и подстановочные типы не совсем одинаковы и не совсем совпадают с экзистенциальными типами (хотя мы знаем, что это не так, довольно сложно точно сказать, что ониявляются).Но на практике они достаточно близки к экзистенциалам, поэтому Scala избегает отображения их на этот тип.

6 голосов
/ 08 сентября 2010
  1. При создании нового универсального типа, скажем, Foo [T], вы должны постараться определить, является ли этот тип ковариантным, контравариантным или инвариантным, и объявить его Foo [+ T], Foo [-T] или Foo [T]. соответственно. По общему признанию это может быть немного трудным. Однако это освобождает пользователя Foo от принятия такого решения каждый раз, когда ему нужно использовать Foo, используя общие границы. Вкратце: предпочитайте декларацию сайта дисперсии, а не сайта вызова, если дисперсия является свойством самого типа.

Кстати, в книге «Программирование в Scala» Мартина Одерского, Лекса Спуна и Билла Веннерса есть несколько отличных рассуждений о дисперсии. См. Главу 19 «Типовая параметризация».

...